blob: e2ddd913c640fa76019f45308434a44f5a3de667 [file] [log] [blame]
Juan Cespedes1c2be911997-06-09 01:12:01 +02001#include <stdio.h>
2#include <errno.h>
Juan Cespedesad783621997-06-10 17:11:33 +02003#include <stdlib.h>
Juan Cespedes1c2be911997-06-09 01:12:01 +02004#include <unistd.h>
5#include <sys/types.h>
6#include <sys/ptrace.h>
7#include <sys/resource.h>
8#include <sys/wait.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <linux/elf.h>
12#include <sys/mman.h>
13#include <string.h>
Juan Cespedes155a4081997-06-11 01:19:35 +020014#include <signal.h>
Juan Cespedes1c2be911997-06-09 01:12:01 +020015
Juan Cespedesad783621997-06-10 17:11:33 +020016static int debug = 0;
17
18struct library_symbol {
19 char * name;
20 unsigned long addr;
21 unsigned char value;
22 struct library_symbol * next;
23};
24
25struct library_symbol * library_symbols = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020026
27int read_elf(char *filename)
28{
29 struct stat sbuf;
30 int fd;
31 void * addr;
32 struct elf32_hdr * hdr;
33 Elf32_Shdr * shdr;
Juan Cespedesad783621997-06-10 17:11:33 +020034 struct elf32_sym * symtab = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020035 int i;
Juan Cespedesad783621997-06-10 17:11:33 +020036 char * strtab = NULL;
37 u_long symtab_len = 0;
Juan Cespedes1c2be911997-06-09 01:12:01 +020038
39 fd = open(filename, O_RDONLY);
40 if (fd==-1) {
41 fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]);
42 exit(1);
43 }
44 if (fstat(fd, &sbuf)==-1) {
45 fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
46 exit(1);
47 }
48 if (sbuf.st_size < sizeof(struct elf32_hdr)) {
49 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
50 exit(1);
51 }
52 addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
53 if (addr==(void*)-1) {
54 fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, sys_errlist[errno]);
55 exit(1);
56 }
57 hdr = addr;
58 if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
59 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
60 exit(1);
61 }
62 for(i=0; i<hdr->e_shnum; i++) {
63 shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
64 if (shdr->sh_type == SHT_DYNSYM) {
65 if (!symtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020066#if 0
67 symtab = (struct elf32_sym *)shdr->sh_addr;
68#else
69 symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
70#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020071 symtab_len = shdr->sh_size;
72 }
73 }
74 if (shdr->sh_type == SHT_STRTAB) {
75 if (!strtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020076#if 0
77 strtab = (char *)(addr + shdr->sh_offset);
78#else
79 strtab = (char *)(addr + shdr->sh_offset);
80#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020081 }
82 }
83 }
Juan Cespedesad783621997-06-10 17:11:33 +020084 if (debug>0) {
85 fprintf(stderr, "symtab: 0x%08x\n", (unsigned)symtab);
86 fprintf(stderr, "symtab_len: %lu\n", symtab_len);
87 fprintf(stderr, "strtab: 0x%08x\n", (unsigned)strtab);
88 }
89 if (!symtab) {
90 return 0;
91 }
92 for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
93 if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
94 struct library_symbol * tmp = library_symbols;
95
96 library_symbols = malloc(sizeof(struct library_symbol));
97 if (!library_symbols) {
98 perror("malloc");
99 exit(1);
100 }
101 library_symbols->addr = ((symtab+i)->st_value);
102 library_symbols->name = strtab+(symtab+i)->st_name;
103 library_symbols->next = tmp;
104 if (debug>0) {
105 fprintf(stderr, "addr: 0x%08x, symbol: \"%s\"\n",
106 (unsigned)((symtab+i)->st_value),
107 (strtab+(symtab+i)->st_name));
108 }
109 }
110 }
111 return 1;
Juan Cespedes1c2be911997-06-09 01:12:01 +0200112}
113
114int main(int argc, char **argv)
115{
116 int pid;
117 int status;
Juan Cespedesad783621997-06-10 17:11:33 +0200118 struct library_symbol * tmp = NULL;
119
120 while ((argc>1) && (argv[1][0] == '-') && (argv[1][2] == '\0')) {
121 switch(argv[1][1]) {
122 case 'd': debug++;
123 break;
124 default: fprintf(stderr, "Unknown option '%c'\n", argv[1][1]);
125 exit(1);
126 }
127 argc--; argv++;
128 }
Juan Cespedes1c2be911997-06-09 01:12:01 +0200129
130 if (argc<2) {
Juan Cespedesad783621997-06-10 17:11:33 +0200131 fprintf(stderr, "Usage: %s [<options>] <program> [<arguments>]\n", argv[0]);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200132 exit(1);
133 }
Juan Cespedesad783621997-06-10 17:11:33 +0200134 if (!read_elf(argv[1])) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200135 fprintf(stderr, "%s: Not dynamically linked\n", argv[0]);
136 exit(1);
137 }
138 pid = fork();
139 if (pid<0) {
140 perror("fork");
141 exit(1);
142 } else if (!pid) {
143 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
144 perror("PTRACE_TRACEME");
145 exit(1);
146 }
147 execvp(argv[1], argv+1);
148 fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]);
149 exit(1);
150 }
151 fprintf(stderr, "pid %u attached\n", pid);
Juan Cespedesad783621997-06-10 17:11:33 +0200152
153 /* Enable breakpoints: */
Juan Cespedes155a4081997-06-11 01:19:35 +0200154 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200155 if (pid==-1) {
156 perror("wait4");
157 exit(1);
158 }
159 fprintf(stderr, "Enabling breakpoints...\n");
160 tmp = library_symbols;
161 while(tmp) {
162 int a;
163 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
164 tmp->value = a & 0xFF;
165 a &= 0xFFFFFF00;
166 a |= 0xCC;
167 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
168 tmp = tmp->next;
169 }
170 ptrace(PTRACE_CONT, pid, 1, 0);
171
Juan Cespedes1c2be911997-06-09 01:12:01 +0200172 while(1) {
Juan Cespedesad783621997-06-10 17:11:33 +0200173 int eip;
174 int function_seen;
175
Juan Cespedes155a4081997-06-11 01:19:35 +0200176 pid = wait4(-1, &status, 0, NULL);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200177 if (pid==-1) {
178 if (errno == ECHILD) {
179 fprintf(stderr, "No more children\n");
180 exit(0);
181 }
182 perror("wait4");
183 exit(1);
184 }
185 if (WIFEXITED(status)) {
186 fprintf(stderr, "pid %u exited\n", pid);
187 continue;
188 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200189 if (WIFSIGNALED(status)) {
190 fprintf(stderr, "pid %u exited on signal %u\n", pid, WTERMSIG(status));
191 continue;
192 }
Juan Cespedesad783621997-06-10 17:11:33 +0200193 if (!WIFSTOPPED(status)) {
194 fprintf(stderr, "pid %u ???\n", pid);
195 continue;
196 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200197 if (WSTOPSIG(status) != SIGTRAP) {
198 fprintf(stderr, "Signal: %u\n", WSTOPSIG(status));
199 ptrace(PTRACE_CONT, pid, 1, WSTOPSIG(status));
200 continue;
201 }
Juan Cespedesad783621997-06-10 17:11:33 +0200202 /* pid is stopped... */
203 eip = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
204/*
205 fprintf(stderr,"EIP = 0x%08x\n", eip);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200206 fprintf(stderr,"EBP = 0x%08x\n", ptrace(PTRACE_PEEKUSR, pid, 4*EBP, 0));
Juan Cespedesad783621997-06-10 17:11:33 +0200207*/
208 tmp = library_symbols;
209 function_seen = 0;
210 while(tmp) {
211 if (eip == tmp->addr+1) {
212 int a;
213 function_seen = 1;
214 fprintf(stderr, "Function: %s\n", tmp->name);
215 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
216 a &= 0xFFFFFF00;
217 a |= tmp->value;
218 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
219 ptrace(PTRACE_POKEUSR, pid, 4*EIP, eip-1);
220 ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
Juan Cespedes155a4081997-06-11 01:19:35 +0200221 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200222 if (pid==-1) {
223 if (errno == ECHILD) {
224 fprintf(stderr, "No more children\n");
225 exit(0);
226 }
227 perror("wait4");
228 exit(1);
229 }
230 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
231 a &= 0xFFFFFF00;
232 a |= 0xCC;
233 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
234 ptrace(PTRACE_CONT, pid, 1, 0);
235 break;
236 }
237 tmp = tmp->next;
238 }
239 if (!function_seen) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200240 fprintf(stderr, "pid %u stopped; continuing it...\n", pid);
241 ptrace(PTRACE_CONT, pid, 1, 0);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200242 }
243 }
244 exit(0);
245}