blob: 432b5eba89075d30713d30714e14e73266dba761 [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 Cespedes24c82531997-06-25 00:02:58 +020016void print_function(const char *, int);
17
Juan Cespedesd3ac65f1997-06-16 00:20:35 +020018int pid;
19
Juan Cespedesad783621997-06-10 17:11:33 +020020static int debug = 0;
21
22struct library_symbol {
23 char * name;
24 unsigned long addr;
25 unsigned char value;
Juan Cespedes24c82531997-06-25 00:02:58 +020026 unsigned long return_addr;
27 unsigned char return_value;
Juan Cespedesad783621997-06-10 17:11:33 +020028 struct library_symbol * next;
29};
30
31struct library_symbol * library_symbols = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020032
Juan Cespedesd3ac65f1997-06-16 00:20:35 +020033static int read_elf(char *filename)
Juan Cespedes1c2be911997-06-09 01:12:01 +020034{
35 struct stat sbuf;
36 int fd;
37 void * addr;
38 struct elf32_hdr * hdr;
39 Elf32_Shdr * shdr;
Juan Cespedesad783621997-06-10 17:11:33 +020040 struct elf32_sym * symtab = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020041 int i;
Juan Cespedesad783621997-06-10 17:11:33 +020042 char * strtab = NULL;
43 u_long symtab_len = 0;
Juan Cespedes1c2be911997-06-09 01:12:01 +020044
45 fd = open(filename, O_RDONLY);
46 if (fd==-1) {
47 fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]);
48 exit(1);
49 }
50 if (fstat(fd, &sbuf)==-1) {
51 fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
52 exit(1);
53 }
54 if (sbuf.st_size < sizeof(struct elf32_hdr)) {
55 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
56 exit(1);
57 }
58 addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
59 if (addr==(void*)-1) {
60 fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, sys_errlist[errno]);
61 exit(1);
62 }
63 hdr = addr;
64 if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
65 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
66 exit(1);
67 }
68 for(i=0; i<hdr->e_shnum; i++) {
69 shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
70 if (shdr->sh_type == SHT_DYNSYM) {
71 if (!symtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020072#if 0
73 symtab = (struct elf32_sym *)shdr->sh_addr;
74#else
75 symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
76#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020077 symtab_len = shdr->sh_size;
78 }
79 }
80 if (shdr->sh_type == SHT_STRTAB) {
81 if (!strtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020082#if 0
83 strtab = (char *)(addr + shdr->sh_offset);
84#else
85 strtab = (char *)(addr + shdr->sh_offset);
86#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020087 }
88 }
89 }
Juan Cespedesad783621997-06-10 17:11:33 +020090 if (debug>0) {
91 fprintf(stderr, "symtab: 0x%08x\n", (unsigned)symtab);
92 fprintf(stderr, "symtab_len: %lu\n", symtab_len);
93 fprintf(stderr, "strtab: 0x%08x\n", (unsigned)strtab);
94 }
95 if (!symtab) {
96 return 0;
97 }
98 for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
99 if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
100 struct library_symbol * tmp = library_symbols;
101
102 library_symbols = malloc(sizeof(struct library_symbol));
103 if (!library_symbols) {
104 perror("malloc");
105 exit(1);
106 }
107 library_symbols->addr = ((symtab+i)->st_value);
108 library_symbols->name = strtab+(symtab+i)->st_name;
109 library_symbols->next = tmp;
110 if (debug>0) {
111 fprintf(stderr, "addr: 0x%08x, symbol: \"%s\"\n",
112 (unsigned)((symtab+i)->st_value),
113 (strtab+(symtab+i)->st_name));
114 }
115 }
116 }
117 return 1;
Juan Cespedes1c2be911997-06-09 01:12:01 +0200118}
119
120int main(int argc, char **argv)
121{
Juan Cespedes1c2be911997-06-09 01:12:01 +0200122 int status;
Juan Cespedesad783621997-06-10 17:11:33 +0200123 struct library_symbol * tmp = NULL;
124
125 while ((argc>1) && (argv[1][0] == '-') && (argv[1][2] == '\0')) {
126 switch(argv[1][1]) {
127 case 'd': debug++;
128 break;
129 default: fprintf(stderr, "Unknown option '%c'\n", argv[1][1]);
130 exit(1);
131 }
132 argc--; argv++;
133 }
Juan Cespedes1c2be911997-06-09 01:12:01 +0200134
135 if (argc<2) {
Juan Cespedesad783621997-06-10 17:11:33 +0200136 fprintf(stderr, "Usage: %s [<options>] <program> [<arguments>]\n", argv[0]);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200137 exit(1);
138 }
Juan Cespedesad783621997-06-10 17:11:33 +0200139 if (!read_elf(argv[1])) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200140 fprintf(stderr, "%s: Not dynamically linked\n", argv[0]);
141 exit(1);
142 }
143 pid = fork();
144 if (pid<0) {
145 perror("fork");
146 exit(1);
147 } else if (!pid) {
148 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
149 perror("PTRACE_TRACEME");
150 exit(1);
151 }
152 execvp(argv[1], argv+1);
153 fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]);
154 exit(1);
155 }
156 fprintf(stderr, "pid %u attached\n", pid);
Juan Cespedesad783621997-06-10 17:11:33 +0200157
158 /* Enable breakpoints: */
Juan Cespedes155a4081997-06-11 01:19:35 +0200159 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200160 if (pid==-1) {
161 perror("wait4");
162 exit(1);
163 }
164 fprintf(stderr, "Enabling breakpoints...\n");
165 tmp = library_symbols;
166 while(tmp) {
167 int a;
168 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
169 tmp->value = a & 0xFF;
170 a &= 0xFFFFFF00;
171 a |= 0xCC;
172 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
173 tmp = tmp->next;
174 }
175 ptrace(PTRACE_CONT, pid, 1, 0);
176
Juan Cespedes1c2be911997-06-09 01:12:01 +0200177 while(1) {
Juan Cespedesad783621997-06-10 17:11:33 +0200178 int eip;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200179 int esp;
Juan Cespedesad783621997-06-10 17:11:33 +0200180 int function_seen;
181
Juan Cespedes155a4081997-06-11 01:19:35 +0200182 pid = wait4(-1, &status, 0, NULL);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200183 if (pid==-1) {
184 if (errno == ECHILD) {
185 fprintf(stderr, "No more children\n");
186 exit(0);
187 }
188 perror("wait4");
189 exit(1);
190 }
191 if (WIFEXITED(status)) {
192 fprintf(stderr, "pid %u exited\n", pid);
193 continue;
194 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200195 if (WIFSIGNALED(status)) {
196 fprintf(stderr, "pid %u exited on signal %u\n", pid, WTERMSIG(status));
197 continue;
198 }
Juan Cespedesad783621997-06-10 17:11:33 +0200199 if (!WIFSTOPPED(status)) {
200 fprintf(stderr, "pid %u ???\n", pid);
201 continue;
202 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200203 if (WSTOPSIG(status) != SIGTRAP) {
204 fprintf(stderr, "Signal: %u\n", WSTOPSIG(status));
205 ptrace(PTRACE_CONT, pid, 1, WSTOPSIG(status));
206 continue;
207 }
Juan Cespedesad783621997-06-10 17:11:33 +0200208 /* pid is stopped... */
209 eip = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200210 esp = ptrace(PTRACE_PEEKUSR, pid, 4*UESP, 0);
211#if 0
Juan Cespedesad783621997-06-10 17:11:33 +0200212 fprintf(stderr,"EIP = 0x%08x\n", eip);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200213 fprintf(stderr,"ESP = 0x%08x\n", esp);
214#endif
215 fprintf(stderr,"[0x%08x] ", ptrace(PTRACE_PEEKTEXT, pid, esp, 0));
Juan Cespedesad783621997-06-10 17:11:33 +0200216 tmp = library_symbols;
217 function_seen = 0;
218 while(tmp) {
219 if (eip == tmp->addr+1) {
220 int a;
221 function_seen = 1;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200222 print_function(tmp->name, esp);
Juan Cespedesad783621997-06-10 17:11:33 +0200223 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
224 a &= 0xFFFFFF00;
225 a |= tmp->value;
226 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
227 ptrace(PTRACE_POKEUSR, pid, 4*EIP, eip-1);
228 ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
Juan Cespedes155a4081997-06-11 01:19:35 +0200229 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200230 if (pid==-1) {
231 if (errno == ECHILD) {
232 fprintf(stderr, "No more children\n");
233 exit(0);
234 }
235 perror("wait4");
236 exit(1);
237 }
238 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
239 a &= 0xFFFFFF00;
240 a |= 0xCC;
241 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
242 ptrace(PTRACE_CONT, pid, 1, 0);
243 break;
244 }
245 tmp = tmp->next;
246 }
247 if (!function_seen) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200248 fprintf(stderr, "pid %u stopped; continuing it...\n", pid);
249 ptrace(PTRACE_CONT, pid, 1, 0);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200250 }
251 }
252 exit(0);
253}