blob: 5bfe3c8a3640a37fe6ed3806c4dade96357e0f2e [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 Cespedesd3ac65f1997-06-16 00:20:35 +020016int pid;
17
Juan Cespedesad783621997-06-10 17:11:33 +020018static int debug = 0;
19
20struct library_symbol {
21 char * name;
22 unsigned long addr;
23 unsigned char value;
24 struct library_symbol * next;
25};
26
27struct library_symbol * library_symbols = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020028
Juan Cespedesd3ac65f1997-06-16 00:20:35 +020029static int read_elf(char *filename)
Juan Cespedes1c2be911997-06-09 01:12:01 +020030{
31 struct stat sbuf;
32 int fd;
33 void * addr;
34 struct elf32_hdr * hdr;
35 Elf32_Shdr * shdr;
Juan Cespedesad783621997-06-10 17:11:33 +020036 struct elf32_sym * symtab = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020037 int i;
Juan Cespedesad783621997-06-10 17:11:33 +020038 char * strtab = NULL;
39 u_long symtab_len = 0;
Juan Cespedes1c2be911997-06-09 01:12:01 +020040
41 fd = open(filename, O_RDONLY);
42 if (fd==-1) {
43 fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]);
44 exit(1);
45 }
46 if (fstat(fd, &sbuf)==-1) {
47 fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
48 exit(1);
49 }
50 if (sbuf.st_size < sizeof(struct elf32_hdr)) {
51 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
52 exit(1);
53 }
54 addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
55 if (addr==(void*)-1) {
56 fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, sys_errlist[errno]);
57 exit(1);
58 }
59 hdr = addr;
60 if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
61 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
62 exit(1);
63 }
64 for(i=0; i<hdr->e_shnum; i++) {
65 shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
66 if (shdr->sh_type == SHT_DYNSYM) {
67 if (!symtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020068#if 0
69 symtab = (struct elf32_sym *)shdr->sh_addr;
70#else
71 symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
72#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020073 symtab_len = shdr->sh_size;
74 }
75 }
76 if (shdr->sh_type == SHT_STRTAB) {
77 if (!strtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020078#if 0
79 strtab = (char *)(addr + shdr->sh_offset);
80#else
81 strtab = (char *)(addr + shdr->sh_offset);
82#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020083 }
84 }
85 }
Juan Cespedesad783621997-06-10 17:11:33 +020086 if (debug>0) {
87 fprintf(stderr, "symtab: 0x%08x\n", (unsigned)symtab);
88 fprintf(stderr, "symtab_len: %lu\n", symtab_len);
89 fprintf(stderr, "strtab: 0x%08x\n", (unsigned)strtab);
90 }
91 if (!symtab) {
92 return 0;
93 }
94 for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
95 if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
96 struct library_symbol * tmp = library_symbols;
97
98 library_symbols = malloc(sizeof(struct library_symbol));
99 if (!library_symbols) {
100 perror("malloc");
101 exit(1);
102 }
103 library_symbols->addr = ((symtab+i)->st_value);
104 library_symbols->name = strtab+(symtab+i)->st_name;
105 library_symbols->next = tmp;
106 if (debug>0) {
107 fprintf(stderr, "addr: 0x%08x, symbol: \"%s\"\n",
108 (unsigned)((symtab+i)->st_value),
109 (strtab+(symtab+i)->st_name));
110 }
111 }
112 }
113 return 1;
Juan Cespedes1c2be911997-06-09 01:12:01 +0200114}
115
116int main(int argc, char **argv)
117{
Juan Cespedes1c2be911997-06-09 01:12:01 +0200118 int status;
Juan Cespedesad783621997-06-10 17:11:33 +0200119 struct library_symbol * tmp = NULL;
120
121 while ((argc>1) && (argv[1][0] == '-') && (argv[1][2] == '\0')) {
122 switch(argv[1][1]) {
123 case 'd': debug++;
124 break;
125 default: fprintf(stderr, "Unknown option '%c'\n", argv[1][1]);
126 exit(1);
127 }
128 argc--; argv++;
129 }
Juan Cespedes1c2be911997-06-09 01:12:01 +0200130
131 if (argc<2) {
Juan Cespedesad783621997-06-10 17:11:33 +0200132 fprintf(stderr, "Usage: %s [<options>] <program> [<arguments>]\n", argv[0]);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200133 exit(1);
134 }
Juan Cespedesad783621997-06-10 17:11:33 +0200135 if (!read_elf(argv[1])) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200136 fprintf(stderr, "%s: Not dynamically linked\n", argv[0]);
137 exit(1);
138 }
139 pid = fork();
140 if (pid<0) {
141 perror("fork");
142 exit(1);
143 } else if (!pid) {
144 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
145 perror("PTRACE_TRACEME");
146 exit(1);
147 }
148 execvp(argv[1], argv+1);
149 fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]);
150 exit(1);
151 }
152 fprintf(stderr, "pid %u attached\n", pid);
Juan Cespedesad783621997-06-10 17:11:33 +0200153
154 /* Enable breakpoints: */
Juan Cespedes155a4081997-06-11 01:19:35 +0200155 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200156 if (pid==-1) {
157 perror("wait4");
158 exit(1);
159 }
160 fprintf(stderr, "Enabling breakpoints...\n");
161 tmp = library_symbols;
162 while(tmp) {
163 int a;
164 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
165 tmp->value = a & 0xFF;
166 a &= 0xFFFFFF00;
167 a |= 0xCC;
168 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
169 tmp = tmp->next;
170 }
171 ptrace(PTRACE_CONT, pid, 1, 0);
172
Juan Cespedes1c2be911997-06-09 01:12:01 +0200173 while(1) {
Juan Cespedesad783621997-06-10 17:11:33 +0200174 int eip;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200175 int esp;
Juan Cespedesad783621997-06-10 17:11:33 +0200176 int function_seen;
177
Juan Cespedes155a4081997-06-11 01:19:35 +0200178 pid = wait4(-1, &status, 0, NULL);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200179 if (pid==-1) {
180 if (errno == ECHILD) {
181 fprintf(stderr, "No more children\n");
182 exit(0);
183 }
184 perror("wait4");
185 exit(1);
186 }
187 if (WIFEXITED(status)) {
188 fprintf(stderr, "pid %u exited\n", pid);
189 continue;
190 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200191 if (WIFSIGNALED(status)) {
192 fprintf(stderr, "pid %u exited on signal %u\n", pid, WTERMSIG(status));
193 continue;
194 }
Juan Cespedesad783621997-06-10 17:11:33 +0200195 if (!WIFSTOPPED(status)) {
196 fprintf(stderr, "pid %u ???\n", pid);
197 continue;
198 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200199 if (WSTOPSIG(status) != SIGTRAP) {
200 fprintf(stderr, "Signal: %u\n", WSTOPSIG(status));
201 ptrace(PTRACE_CONT, pid, 1, WSTOPSIG(status));
202 continue;
203 }
Juan Cespedesad783621997-06-10 17:11:33 +0200204 /* pid is stopped... */
205 eip = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200206 esp = ptrace(PTRACE_PEEKUSR, pid, 4*UESP, 0);
207#if 0
Juan Cespedesad783621997-06-10 17:11:33 +0200208 fprintf(stderr,"EIP = 0x%08x\n", eip);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200209 fprintf(stderr,"ESP = 0x%08x\n", esp);
210#endif
211 fprintf(stderr,"[0x%08x] ", ptrace(PTRACE_PEEKTEXT, pid, esp, 0));
Juan Cespedesad783621997-06-10 17:11:33 +0200212 tmp = library_symbols;
213 function_seen = 0;
214 while(tmp) {
215 if (eip == tmp->addr+1) {
216 int a;
217 function_seen = 1;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200218 print_function(tmp->name, esp);
Juan Cespedesad783621997-06-10 17:11:33 +0200219 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
220 a &= 0xFFFFFF00;
221 a |= tmp->value;
222 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
223 ptrace(PTRACE_POKEUSR, pid, 4*EIP, eip-1);
224 ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
Juan Cespedes155a4081997-06-11 01:19:35 +0200225 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200226 if (pid==-1) {
227 if (errno == ECHILD) {
228 fprintf(stderr, "No more children\n");
229 exit(0);
230 }
231 perror("wait4");
232 exit(1);
233 }
234 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
235 a &= 0xFFFFFF00;
236 a |= 0xCC;
237 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
238 ptrace(PTRACE_CONT, pid, 1, 0);
239 break;
240 }
241 tmp = tmp->next;
242 }
243 if (!function_seen) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200244 fprintf(stderr, "pid %u stopped; continuing it...\n", pid);
245 ptrace(PTRACE_CONT, pid, 1, 0);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200246 }
247 }
248 exit(0);
249}