1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc Declaration for Linux kernel compatibility
3433d6423SLionel Sambuc */
4433d6423SLionel Sambuc
5433d6423SLionel Sambuc #include <assert.h>
6433d6423SLionel Sambuc #include <stdarg.h>
7433d6423SLionel Sambuc #include <stdio.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <sys/types.h>
10433d6423SLionel Sambuc #include <sys/ptrace.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc #include "extra.h"
13433d6423SLionel Sambuc
14433d6423SLionel Sambuc pid_t victim_pid= -1;
15433d6423SLionel Sambuc char *victim_exe= NULL;
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc #define TRAP_BIT (0x80000000)
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc static struct nlist *exe_nlist;
20433d6423SLionel Sambuc static int exe_nlist_n;
21433d6423SLionel Sambuc
printk(char * fmt,...)22433d6423SLionel Sambuc void printk(char *fmt, ...)
23433d6423SLionel Sambuc {
24433d6423SLionel Sambuc va_list ap;
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc va_start(ap, fmt);
27433d6423SLionel Sambuc vfprintf(stderr, fmt, ap);
28433d6423SLionel Sambuc va_end(ap);
29433d6423SLionel Sambuc }
30433d6423SLionel Sambuc
kallsyms_address_to_symbol(db_expr_t off,const char ** mod_name,unsigned long * mod_start,unsigned long * mod_end,const char ** sec_name,unsigned long * sec_start,unsigned long * sec_end,const char ** sym_name,unsigned long * sym_start,unsigned long * sym_end)31433d6423SLionel Sambuc int kallsyms_address_to_symbol(db_expr_t off,
32433d6423SLionel Sambuc const char * *mod_name, unsigned long *mod_start, unsigned long *mod_end,
33433d6423SLionel Sambuc const char * *sec_name, unsigned long *sec_start, unsigned long *sec_end,
34433d6423SLionel Sambuc const char * *sym_name, unsigned long *sym_start, unsigned long *sym_end)
35433d6423SLionel Sambuc {
36433d6423SLionel Sambuc static char name[64];
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc int i;
39433d6423SLionel Sambuc unsigned long btext, etext;
40433d6423SLionel Sambuc struct nlist *below, *above;
41433d6423SLionel Sambuc
42433d6423SLionel Sambuc off &= ~TRAP_BIT;
43433d6423SLionel Sambuc load_nlist(victim_exe, &btext, &etext);
44433d6423SLionel Sambuc below= above= NULL;
45433d6423SLionel Sambuc for (i= 0; i<exe_nlist_n; i++)
46433d6423SLionel Sambuc {
47433d6423SLionel Sambuc if (exe_nlist[i].n_type != N_TEXT)
48433d6423SLionel Sambuc continue;
49433d6423SLionel Sambuc if (exe_nlist[i].n_value <= off)
50433d6423SLionel Sambuc {
51433d6423SLionel Sambuc if (!below || exe_nlist[i].n_value > below->n_value)
52433d6423SLionel Sambuc below= &exe_nlist[i];
53433d6423SLionel Sambuc }
54433d6423SLionel Sambuc if (exe_nlist[i].n_value > off)
55433d6423SLionel Sambuc {
56433d6423SLionel Sambuc if (!above || exe_nlist[i].n_value < above->n_value)
57433d6423SLionel Sambuc above= &exe_nlist[i];
58433d6423SLionel Sambuc }
59433d6423SLionel Sambuc }
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc btext |= TRAP_BIT;
62433d6423SLionel Sambuc etext |= TRAP_BIT;
63433d6423SLionel Sambuc
64433d6423SLionel Sambuc *mod_name = victim_exe;
65433d6423SLionel Sambuc *mod_start = btext;
66433d6423SLionel Sambuc *mod_end = etext;
67433d6423SLionel Sambuc *sec_name = ".text";
68433d6423SLionel Sambuc *sec_start = btext;
69433d6423SLionel Sambuc *sec_end = etext;
70433d6423SLionel Sambuc
71433d6423SLionel Sambuc assert(below && above);
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc strncpy(name, below->n_name, sizeof(name)-1);
74433d6423SLionel Sambuc name[sizeof(name)-1]= '\0';
75433d6423SLionel Sambuc *sym_name= name;
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc *sym_start= below->n_value | TRAP_BIT;
78433d6423SLionel Sambuc *sym_end= above->n_value | TRAP_BIT;
79433d6423SLionel Sambuc
80433d6423SLionel Sambuc return 1;
81433d6423SLionel Sambuc }
82433d6423SLionel Sambuc
text_read_ul(void * addr)83433d6423SLionel Sambuc unsigned long text_read_ul(void *addr)
84433d6423SLionel Sambuc {
85433d6423SLionel Sambuc int i;
86433d6423SLionel Sambuc unsigned long value;
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc for (i= 0; i<sizeof(value); i++)
89433d6423SLionel Sambuc {
90433d6423SLionel Sambuc ((unsigned char *)&value)[i]= text_read_ub((char *)addr+i);
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc return value;
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc
text_read_ub(void * addr)95433d6423SLionel Sambuc unsigned char text_read_ub(void *addr)
96433d6423SLionel Sambuc {
97433d6423SLionel Sambuc int v;
98433d6423SLionel Sambuc unsigned long vaddr;
99433d6423SLionel Sambuc
100433d6423SLionel Sambuc vaddr= (unsigned long)addr;
101433d6423SLionel Sambuc vaddr &= ~TRAP_BIT;
102*d0055759SDavid van Moolenbroek v= ptrace(T_READB_INS, victim_pid, (void *)vaddr, 0);
103433d6423SLionel Sambuc if (v < 0)
104433d6423SLionel Sambuc {
105433d6423SLionel Sambuc fprintf(stderr,
106433d6423SLionel Sambuc "text_read_ub: trace T_READB_INS failed on pid %d, addr 0x%lx: %s\n",
107433d6423SLionel Sambuc victim_pid, vaddr, strerror(errno));
108433d6423SLionel Sambuc exit(1);
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc return v;
111433d6423SLionel Sambuc }
112433d6423SLionel Sambuc
text_write_ul(void * addr,unsigned long value)113433d6423SLionel Sambuc void text_write_ul(void *addr, unsigned long value)
114433d6423SLionel Sambuc {
115433d6423SLionel Sambuc int i;
116433d6423SLionel Sambuc
117433d6423SLionel Sambuc for (i= 0; i<sizeof(value); i++)
118433d6423SLionel Sambuc {
119433d6423SLionel Sambuc text_write_ub((char *)addr+i, ((unsigned char *)&value)[i]);
120433d6423SLionel Sambuc }
121433d6423SLionel Sambuc }
122433d6423SLionel Sambuc
text_write_ub(void * addr,unsigned char value)123433d6423SLionel Sambuc void text_write_ub(void *addr, unsigned char value)
124433d6423SLionel Sambuc {
125433d6423SLionel Sambuc int v;
126433d6423SLionel Sambuc unsigned long vaddr;
127433d6423SLionel Sambuc
128433d6423SLionel Sambuc vaddr= (unsigned long)addr;
129433d6423SLionel Sambuc vaddr &= ~TRAP_BIT;
130*d0055759SDavid van Moolenbroek v= ptrace(T_WRITEB_INS, victim_pid, (void *)vaddr, value);
131433d6423SLionel Sambuc if (v < 0)
132433d6423SLionel Sambuc {
133433d6423SLionel Sambuc fprintf(stderr,
134433d6423SLionel Sambuc "text_read_ub: trace T_WRITEB_INS failed on pid %d, addr 0x%lx: %s\n",
135433d6423SLionel Sambuc victim_pid, vaddr, strerror(errno));
136433d6423SLionel Sambuc exit(1);
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc }
139433d6423SLionel Sambuc
load_nlist(exe_name,btextp,etextp)140433d6423SLionel Sambuc void load_nlist(exe_name, btextp, etextp)
141433d6423SLionel Sambuc char *exe_name;
142433d6423SLionel Sambuc unsigned long *btextp;
143433d6423SLionel Sambuc unsigned long *etextp;
144433d6423SLionel Sambuc {
145433d6423SLionel Sambuc int i;
146433d6423SLionel Sambuc unsigned long btext, etext;
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc if (!exe_nlist)
149433d6423SLionel Sambuc {
150433d6423SLionel Sambuc exe_nlist_n= read_nlist(exe_name, &exe_nlist);
151433d6423SLionel Sambuc if (exe_nlist_n <= 0)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc if (exe_nlist_n == -1)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc fprintf(stderr,
156433d6423SLionel Sambuc "error reading name list from '%s': %s\n",
157433d6423SLionel Sambuc exe_name, strerror(errno));
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc else
160433d6423SLionel Sambuc fprintf(stderr, "no name list in '%s'\n",
161433d6423SLionel Sambuc exe_name);
162433d6423SLionel Sambuc exit(1);
163433d6423SLionel Sambuc }
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc
166433d6423SLionel Sambuc if (!btextp && !etextp)
167433d6423SLionel Sambuc return;
168433d6423SLionel Sambuc
169433d6423SLionel Sambuc etext= 0;
170433d6423SLionel Sambuc btext= (unsigned long)-1;
171433d6423SLionel Sambuc for (i= 0; i<exe_nlist_n; i++)
172433d6423SLionel Sambuc {
173433d6423SLionel Sambuc if (exe_nlist[i].n_type != N_TEXT)
174433d6423SLionel Sambuc continue;
175433d6423SLionel Sambuc if (exe_nlist[i].n_value < btext)
176433d6423SLionel Sambuc btext= exe_nlist[i].n_value;
177433d6423SLionel Sambuc if (exe_nlist[i].n_value > etext)
178433d6423SLionel Sambuc etext= exe_nlist[i].n_value;
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc
181433d6423SLionel Sambuc if (btext >= etext)
182433d6423SLionel Sambuc {
183433d6423SLionel Sambuc fprintf(stderr, "Bad btext (0x%lx) or etext (0x%lx) in %s\n",
184433d6423SLionel Sambuc btext, etext, exe_name);
185433d6423SLionel Sambuc exit(1);
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc
188433d6423SLionel Sambuc btext |= TRAP_BIT;
189433d6423SLionel Sambuc etext |= TRAP_BIT;
190433d6423SLionel Sambuc
191433d6423SLionel Sambuc if (btextp)
192433d6423SLionel Sambuc *btextp= btext;
193433d6423SLionel Sambuc if (etextp)
194433d6423SLionel Sambuc *etextp= etext;
195433d6423SLionel Sambuc }
196