blob: dda96836cfd8dce1182472b80155be9159caf9e4 [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 Cespedes5b2f9811997-07-17 00:05:10 +020016extern void print_function(const char *, int);
Juan Cespedes24c82531997-06-25 00:02:58 +020017
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;
26 struct library_symbol * next;
27};
28
Juan Cespedes5b2f9811997-07-17 00:05:10 +020029FILE * output = stderr;
30
31unsigned long return_addr;
32unsigned char return_value;
33struct library_symbol * current_symbol;
34
Juan Cespedesad783621997-06-10 17:11:33 +020035struct library_symbol * library_symbols = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020036
Juan Cespedesd3ac65f1997-06-16 00:20:35 +020037static int read_elf(char *filename)
Juan Cespedes1c2be911997-06-09 01:12:01 +020038{
39 struct stat sbuf;
40 int fd;
41 void * addr;
42 struct elf32_hdr * hdr;
43 Elf32_Shdr * shdr;
Juan Cespedesad783621997-06-10 17:11:33 +020044 struct elf32_sym * symtab = NULL;
Juan Cespedes1c2be911997-06-09 01:12:01 +020045 int i;
Juan Cespedesad783621997-06-10 17:11:33 +020046 char * strtab = NULL;
47 u_long symtab_len = 0;
Juan Cespedes1c2be911997-06-09 01:12:01 +020048
49 fd = open(filename, O_RDONLY);
50 if (fd==-1) {
51 fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]);
52 exit(1);
53 }
54 if (fstat(fd, &sbuf)==-1) {
55 fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
56 exit(1);
57 }
58 if (sbuf.st_size < sizeof(struct elf32_hdr)) {
59 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
60 exit(1);
61 }
62 addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
63 if (addr==(void*)-1) {
64 fprintf(stderr, "Can't mmap \"%s\": %s\n", filename, sys_errlist[errno]);
65 exit(1);
66 }
67 hdr = addr;
68 if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
69 fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
70 exit(1);
71 }
72 for(i=0; i<hdr->e_shnum; i++) {
73 shdr = addr + hdr->e_shoff + i*hdr->e_shentsize;
74 if (shdr->sh_type == SHT_DYNSYM) {
75 if (!symtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020076#if 0
77 symtab = (struct elf32_sym *)shdr->sh_addr;
78#else
79 symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
80#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020081 symtab_len = shdr->sh_size;
82 }
83 }
84 if (shdr->sh_type == SHT_STRTAB) {
85 if (!strtab) {
Juan Cespedesad783621997-06-10 17:11:33 +020086#if 0
87 strtab = (char *)(addr + shdr->sh_offset);
88#else
89 strtab = (char *)(addr + shdr->sh_offset);
90#endif
Juan Cespedes1c2be911997-06-09 01:12:01 +020091 }
92 }
93 }
Juan Cespedesad783621997-06-10 17:11:33 +020094 if (debug>0) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +020095 fprintf(output, "symtab: 0x%08x\n", (unsigned)symtab);
96 fprintf(output, "symtab_len: %lu\n", symtab_len);
97 fprintf(output, "strtab: 0x%08x\n", (unsigned)strtab);
Juan Cespedesad783621997-06-10 17:11:33 +020098 }
99 if (!symtab) {
100 return 0;
101 }
102 for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
103 if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
104 struct library_symbol * tmp = library_symbols;
105
106 library_symbols = malloc(sizeof(struct library_symbol));
107 if (!library_symbols) {
108 perror("malloc");
109 exit(1);
110 }
111 library_symbols->addr = ((symtab+i)->st_value);
112 library_symbols->name = strtab+(symtab+i)->st_name;
113 library_symbols->next = tmp;
114 if (debug>0) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200115 fprintf(output, "addr: 0x%08x, symbol: \"%s\"\n",
Juan Cespedesad783621997-06-10 17:11:33 +0200116 (unsigned)((symtab+i)->st_value),
117 (strtab+(symtab+i)->st_name));
118 }
119 }
120 }
121 return 1;
Juan Cespedes1c2be911997-06-09 01:12:01 +0200122}
123
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200124static void insert_breakpoint(int pid, unsigned long addr, unsigned char * value)
125{
126}
127
128static void delete_breakpoint(int pid, unsigned long addr, unsigned char * value)
129{
130}
131
132static void usage(void)
133{
134 fprintf(stderr," Usage: ltrace [-d][-o output] <program> [<arguments>...]\n");
135}
136
Juan Cespedes1c2be911997-06-09 01:12:01 +0200137int main(int argc, char **argv)
138{
Juan Cespedes1c2be911997-06-09 01:12:01 +0200139 int status;
Juan Cespedesad783621997-06-10 17:11:33 +0200140 struct library_symbol * tmp = NULL;
141
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200142 while ((argc>2) && (argv[1][0] == '-') && (argv[1][2] == '\0')) {
Juan Cespedesad783621997-06-10 17:11:33 +0200143 switch(argv[1][1]) {
144 case 'd': debug++;
145 break;
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200146 case 'o': output = fopen(argv[2], "w");
147 if (!output) {
148 fprintf(stderr, "Can't open %s for output: %s\n", argv[2], sys_errlist[errno]);
149 exit(1);
150 }
151 argc--; argv++;
152 break;
Juan Cespedesad783621997-06-10 17:11:33 +0200153 default: fprintf(stderr, "Unknown option '%c'\n", argv[1][1]);
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200154 usage();
Juan Cespedesad783621997-06-10 17:11:33 +0200155 exit(1);
156 }
157 argc--; argv++;
158 }
Juan Cespedes1c2be911997-06-09 01:12:01 +0200159
160 if (argc<2) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200161 usage();
Juan Cespedes1c2be911997-06-09 01:12:01 +0200162 exit(1);
163 }
Juan Cespedesad783621997-06-10 17:11:33 +0200164 if (!read_elf(argv[1])) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200165 fprintf(stderr, "%s: Not dynamically linked\n", argv[1]);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200166 exit(1);
167 }
168 pid = fork();
169 if (pid<0) {
170 perror("fork");
171 exit(1);
172 } else if (!pid) {
173 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
174 perror("PTRACE_TRACEME");
175 exit(1);
176 }
177 execvp(argv[1], argv+1);
178 fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]);
179 exit(1);
180 }
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200181 fprintf(output, "pid %u attached\n", pid);
Juan Cespedesad783621997-06-10 17:11:33 +0200182
183 /* Enable breakpoints: */
Juan Cespedes155a4081997-06-11 01:19:35 +0200184 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200185 if (pid==-1) {
186 perror("wait4");
187 exit(1);
188 }
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200189 fprintf(output, "Enabling breakpoints...\n");
Juan Cespedesad783621997-06-10 17:11:33 +0200190 tmp = library_symbols;
191 while(tmp) {
192 int a;
193 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
194 tmp->value = a & 0xFF;
195 a &= 0xFFFFFF00;
196 a |= 0xCC;
197 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
198 tmp = tmp->next;
199 }
200 ptrace(PTRACE_CONT, pid, 1, 0);
201
Juan Cespedes1c2be911997-06-09 01:12:01 +0200202 while(1) {
Juan Cespedesad783621997-06-10 17:11:33 +0200203 int eip;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200204 int esp;
Juan Cespedesad783621997-06-10 17:11:33 +0200205 int function_seen;
206
Juan Cespedes155a4081997-06-11 01:19:35 +0200207 pid = wait4(-1, &status, 0, NULL);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200208 if (pid==-1) {
209 if (errno == ECHILD) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200210 fprintf(output, "No more children\n");
Juan Cespedes1c2be911997-06-09 01:12:01 +0200211 exit(0);
212 }
213 perror("wait4");
214 exit(1);
215 }
216 if (WIFEXITED(status)) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200217 fprintf(output, "pid %u exited\n", pid);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200218 continue;
219 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200220 if (WIFSIGNALED(status)) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200221 fprintf(output, "pid %u exited on signal %u\n", pid, WTERMSIG(status));
Juan Cespedes155a4081997-06-11 01:19:35 +0200222 continue;
223 }
Juan Cespedesad783621997-06-10 17:11:33 +0200224 if (!WIFSTOPPED(status)) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200225 fprintf(output, "pid %u ???\n", pid);
Juan Cespedesad783621997-06-10 17:11:33 +0200226 continue;
227 }
Juan Cespedes155a4081997-06-11 01:19:35 +0200228 if (WSTOPSIG(status) != SIGTRAP) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200229 fprintf(output, "Signal: %u\n", WSTOPSIG(status));
Juan Cespedes155a4081997-06-11 01:19:35 +0200230 ptrace(PTRACE_CONT, pid, 1, WSTOPSIG(status));
231 continue;
232 }
Juan Cespedesad783621997-06-10 17:11:33 +0200233 /* pid is stopped... */
234 eip = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200235 esp = ptrace(PTRACE_PEEKUSR, pid, 4*UESP, 0);
236#if 0
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200237 fprintf(output,"EIP = 0x%08x\n", eip);
238 fprintf(output,"ESP = 0x%08x\n", esp);
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200239#endif
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200240 fprintf(output,"[0x%08x] ", ptrace(PTRACE_PEEKTEXT, pid, esp, 0));
Juan Cespedesad783621997-06-10 17:11:33 +0200241 tmp = library_symbols;
242 function_seen = 0;
243 while(tmp) {
244 if (eip == tmp->addr+1) {
245 int a;
246 function_seen = 1;
Juan Cespedesd3ac65f1997-06-16 00:20:35 +0200247 print_function(tmp->name, esp);
Juan Cespedesad783621997-06-10 17:11:33 +0200248 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
249 a &= 0xFFFFFF00;
250 a |= tmp->value;
251 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
252 ptrace(PTRACE_POKEUSR, pid, 4*EIP, eip-1);
253 ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
Juan Cespedes155a4081997-06-11 01:19:35 +0200254 pid = wait4(-1, &status, 0, NULL);
Juan Cespedesad783621997-06-10 17:11:33 +0200255 if (pid==-1) {
256 if (errno == ECHILD) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200257 fprintf(output, "No more children\n");
Juan Cespedesad783621997-06-10 17:11:33 +0200258 exit(0);
259 }
260 perror("wait4");
261 exit(1);
262 }
263 a = ptrace(PTRACE_PEEKTEXT, pid, tmp->addr, 0);
264 a &= 0xFFFFFF00;
265 a |= 0xCC;
266 ptrace(PTRACE_POKETEXT, pid, tmp->addr, a);
267 ptrace(PTRACE_CONT, pid, 1, 0);
268 break;
269 }
270 tmp = tmp->next;
271 }
272 if (!function_seen) {
Juan Cespedes5b2f9811997-07-17 00:05:10 +0200273 fprintf(output, "pid %u stopped; continuing it...\n", pid);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200274 ptrace(PTRACE_CONT, pid, 1, 0);
Juan Cespedes1c2be911997-06-09 01:12:01 +0200275 }
276 }
277 exit(0);
278}