blob: af5773f418a4c61ed98ca4cb43522f0250554879 [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>
14
Juan Cespedesad783621997-06-10 17:11:33 +020015static int debug = 0;
16
17struct library_symbol {
18 char * name;
19 unsigned long addr;
20 unsigned char value;
21 struct library_symbol * next;
22};
23
24struct library_symbol * library_symbols = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020025
26int read_elf(char *filename)
27{
28 struct stat sbuf;
29 int fd;
30 void * addr;
31 struct elf32_hdr * hdr;
32 Elf32_Shdr * shdr;
Juan Cespedesad783621997-06-10 17:11:33 +020033 struct elf32_sym * symtab = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020034 int i;
Juan Cespedesad783621997-06-10 17:11:33 +020035 char * strtab = NULL;
36 u_long symtab_len = 0;
Juan Cespedes1c2be911997-06-09 01:12:01 +020037
38 fd = open(filename, O_RDONLY);
39 if (fd==-1) {
40 fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]);
41 exit(1);
42 }
43 if (fstat(fd, &sbuf)==-1) {
44 fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
45 exit(1);
46 }
47 if (sbuf.st_size < sizeof(struct elf32_hdr)) {
48 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
49 exit(1);
50 }
51 addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
52 if (addr==(void*)-1) {
53 fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, sys_errlist[errno]);
54 exit(1);
55 }
56 hdr = addr;
57 if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
58 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
59 exit(1);
60 }
61 for(i=0; i<hdr->e_shnum; i++) {
62 shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
63 if (shdr->sh_type == SHT_DYNSYM) {
64 if (!symtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020065#if 0
66 symtab = (struct elf32_sym *)shdr->sh_addr;
67#else
68 symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
69#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020070 symtab_len = shdr->sh_size;
71 }
72 }
73 if (shdr->sh_type == SHT_STRTAB) {
74 if (!strtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020075#if 0
76 strtab = (char *)(addr + shdr->sh_offset);
77#else
78 strtab = (char *)(addr + shdr->sh_offset);
79#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020080 }
81 }
82 }
Juan Cespedesad783621997-06-10 17:11:33 +020083 if (debug>0) {
84 fprintf(stderr, "symtab: 0x%08x\n", (unsigned)symtab);
85 fprintf(stderr, "symtab_len: %lu\n", symtab_len);
86 fprintf(stderr, "strtab: 0x%08x\n", (unsigned)strtab);
87 }
88 if (!symtab) {
89 return 0;
90 }
91 for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
92 if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
93 struct library_symbol * tmp = library_symbols;
94
95 library_symbols = malloc(sizeof(struct library_symbol));
96 if (!library_symbols) {
97 perror("malloc");
98 exit(1);
99 }
100 library_symbols->addr = ((symtab+i)->st_value);
101 library_symbols->name = strtab+(symtab+i)->st_name;
102 library_symbols->next = tmp;
103 if (debug>0) {
104 fprintf(stderr, "addr: 0x%08x, symbol: \"%s\"\n",
105 (unsigned)((symtab+i)->st_value),
106 (strtab+(symtab+i)->st_name));
107 }
108 }
109 }
110 return 1;
Juan Cespedes1c2be911997-06-09 01:12:01 +0200111}
112
113int main(int argc, char **argv)
114{
115 int pid;
116 int status;
117 struct rusage ru;
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: */
154 pid = wait4(-1, &status, 0, &ru);
155 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 Cespedes1c2be911997-06-09 01:12:01 +0200176 pid = wait4(-1, &status, 0, &ru);
177 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 Cespedesad783621997-06-10 17:11:33 +0200189 if (!WIFSTOPPED(status)) {
190 fprintf(stderr, "pid %u ???\n", pid);
191 continue;
192 }
193 /* pid is stopped... */
194 eip = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
195/*
196 fprintf(stderr,"EIP = 0x%08x\n", eip);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200197 fprintf(stderr,"EBP = 0x%08x\n", ptrace(PTRACE_PEEKUSR, pid, 4*EBP, 0));
Juan Cespedesad783621997-06-10 17:11:33 +0200198*/
199 tmp = library_symbols;
200 function_seen = 0;
201 while(tmp) {
202 if (eip == tmp->addr+1) {
203 int a;
204 function_seen = 1;
205 fprintf(stderr, "Function: %s\n", tmp->name);
206 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
207 a &= 0xFFFFFF00;
208 a |= tmp->value;
209 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
210 ptrace(PTRACE_POKEUSR, pid, 4*EIP, eip-1);
211 ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
212 pid = wait4(-1, &status, 0, &ru);
213 if (pid==-1) {
214 if (errno == ECHILD) {
215 fprintf(stderr, "No more children\n");
216 exit(0);
217 }
218 perror("wait4");
219 exit(1);
220 }
221 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
222 a &= 0xFFFFFF00;
223 a |= 0xCC;
224 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
225 ptrace(PTRACE_CONT, pid, 1, 0);
226 break;
227 }
228 tmp = tmp->next;
229 }
230 if (!function_seen) {
Juan Cespedes1c2be911997-06-09 01:12:01 +0200231 fprintf(stderr, "pid %u stopped; continuing it...\n", pid);
232 ptrace(PTRACE_CONT, pid, 1, 0);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200233 }
234 }
235 exit(0);
236}