Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <mach.h>
4 #include "stabs.h"
6 static int
7 strcmpcolon(char *a, char *bcolon)
8 {
9 int i, len;
10 char *p;
12 p = strchr(bcolon, ':');
13 if(p == nil)
14 return strcmp(a, bcolon);
15 len = p-bcolon;
16 i = strncmp(a, bcolon, len);
17 if(i)
18 return i;
19 if(a[len] == 0)
20 return 0;
21 return 1;
22 }
24 static int
25 stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i)
26 {
27 char *p;
29 /*
30 * Zero out the : to avoid allocating a new name string.
31 * The type info can be found by looking past the NUL.
32 * This is going to get us in trouble...
33 */
34 if((p = strchr(stab->name, ':')) != nil)
35 *p++ = 0;
36 else
37 p = stab->name+strlen(stab->name)+1;
39 sym->name = stab->name;
40 sym->u.stabs.dir = dir;
41 sym->u.stabs.file = file;
42 sym->u.stabs.i = i;
43 switch(stab->type){
44 default:
45 return -1;
46 case N_FUN:
47 sym->class = CTEXT;
48 switch(*p){
49 default:
50 return -1;
51 case 'F': /* global function */
52 sym->type = 'T';
53 break;
54 case 'Q': /* static procedure */
55 case 'f': /* static function */
56 case 'I': /* nested procedure */
57 case 'J': /* nested function */
58 sym->type = 't';
59 break;
60 }
61 sym->loc.type = LADDR;
62 sym->loc.addr = stab->value;
63 break;
64 case N_GSYM:
65 case N_PSYM:
66 case N_LSYM:
67 case N_LCSYM:
68 sym->class = CDATA;
69 sym->loc.type = LADDR;
70 sym->loc.addr = stab->value;
71 switch(*p){
72 default:
73 return -1;
74 case 'S': /* file-scope static variable */
75 sym->type = 'd';
76 break;
77 case 'G': /* global variable */
78 sym->type = 'D';
79 sym->loc.type = LNONE;
80 break;
81 case 'r': /* register variable */
82 sym->class = CAUTO;
83 sym->type = 'a';
84 sym->loc.type = LREG;
85 sym->loc.reg = "XXX";
86 break;
87 case 's': /* local variable */
88 sym->class = CAUTO;
89 sym->type = 'a';
90 sym->loc.type = LOFFSET;
91 sym->loc.offset = stab->value;
92 sym->loc.reg = "XXX";
93 break;
94 case 'a': /* by reference */
95 case 'D': /* f.p. parameter */
96 case 'i': /* register parameter */
97 case 'p': /* "normal" parameter */
98 case 'P': /* register parameter */
99 case 'v': /* by reference */
100 case 'X': /* function return variable */
101 sym->class = CPARAM;
102 sym->type = 'p';
103 if(*p == 'i'){
104 sym->loc.type = LREG;
105 sym->loc.reg = "XXX";
106 }else{
107 sym->loc.type = LOFFSET;
108 sym->loc.offset = stab->value;
109 sym->loc.reg = "XXX";
111 break;
113 break;
115 return 0;
118 static int
119 stabssyminit(Fhdr *fp)
121 int i;
122 char *dir, *file;
123 Stab *stabs;
124 StabSym sym, lastfun;
125 Symbol s, *fun;
126 char **inc, **xinc;
127 int ninc, minc;
128 int locals, autos, params;
130 stabs = &fp->stabs;
131 if(stabs == nil){
132 werrstr("no stabs info");
133 return -1;
136 dir = nil;
137 file = nil;
138 inc = nil;
139 fun = nil;
140 ninc = 0;
141 minc = 0;
142 locals = 0;
143 params = 0;
144 autos = 0;
145 memset(&lastfun, 0, sizeof lastfun);
146 for(i=0; stabsym(stabs, i, &sym)>=0; i++){
147 switch(sym.type){
148 case N_SO:
149 if(sym.name == nil || *sym.name == 0){
150 file = nil;
151 break;
153 if(sym.name[strlen(sym.name)-1] == '/')
154 dir = sym.name;
155 else
156 file = sym.name;
157 break;
158 case N_BINCL:
159 if(ninc >= minc){
160 xinc = realloc(inc, (ninc+32)*sizeof(inc[0]));
161 if(xinc){
162 memset(xinc+ninc, 0, 32*sizeof(inc[0]));
163 inc = xinc;
165 ninc += 32;
167 if(ninc < minc)
168 inc[ninc] = sym.name;
169 ninc++;
170 break;
171 case N_EINCL:
172 if(ninc > 0)
173 ninc--;
174 break;
175 case N_EXCL:
176 /* condensed include - same effect as previous BINCL/EINCL pair */
177 break;
178 case N_GSYM: /* global variable */
179 /* only includes type, so useless for now */
180 break;
181 case N_FUN:
182 if(sym.name == nil){
183 /* marks end of function */
184 if(fun){
185 fun->hiloc.type = LADDR;
186 fun->hiloc.addr = fun->loc.addr + sym.value;
188 break;
190 if(fun && lastfun.value==sym.value && lastfun.name==sym.name){
191 fun->u.stabs.locals = i;
192 break;
194 /* create new symbol, add it */
195 lastfun = sym;
196 fun = nil;
197 if(stabcvtsym(&sym, &s, dir, file, i) < 0)
198 continue;
199 if((fun = _addsym(fp, &s)) == nil)
200 goto err;
201 locals = 0;
202 params = 0;
203 autos = 0;
204 break;
205 case N_PSYM:
206 case N_LSYM:
207 case N_LCSYM:
208 if(fun){
209 if(fun->u.stabs.frameptr == -1){
210 /*
211 * Try to distinguish functions with a real frame pointer
212 * from functions with a virtual frame pointer, based on
213 * whether the first parameter is in the right location and
214 * whether the autos have negative offsets.
216 * This heuristic works most of the time. On the 386, we
217 * cannot distinguish between a v. function with no autos
218 * but a frame of size 4 and a f.p. function with no autos and
219 * no frame. Anything else we'll get right.
221 * Another way to go about this would be to have
222 * mach-specific functions to inspect the function
223 * prologues when we're not sure. What we have
224 * already should be enough, though.
225 */
226 if(params==0 && sym.type == N_PSYM){
227 if(sym.value != 8 && sym.value >= 4){
228 /* XXX 386 specific, but let's find another system before generalizing */
229 fun->u.stabs.frameptr = 0;
230 fun->u.stabs.framesize = sym.value - 4;
232 }else if(sym.type == N_LSYM){
233 if((int32)sym.value >= 0){
234 fun->u.stabs.frameptr = 0;
235 if(params)
236 fun->u.stabs.framesize = 8 - 4;
237 }else
238 fun->u.stabs.frameptr = 1;
241 if(sym.type == N_PSYM)
242 params++;
243 if(sym.type == N_LSYM)
244 autos++;
246 break;
248 case N_STSYM: /* static file-scope variable */
249 /* create new symbol, add it */
250 if(stabcvtsym(&sym, &s, dir, file, i) < 0)
251 continue;
252 if(_addsym(fp, &s) == nil)
253 goto err;
254 break;
257 USED(locals);
258 free(inc);
259 return 0;
261 err:
262 free(inc);
263 return -1;
266 static int
267 stabspc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *pline)
269 int i;
270 Symbol *s;
271 StabSym ss;
272 ulong line, basepc;
273 Loc l;
275 l.type = LADDR;
276 l.addr = pc;
277 if((s = ffindsym(fhdr, l, CTEXT)) == nil
278 || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
279 return -1;
281 line = ss.desc;
282 basepc = ss.value;
283 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
284 if(ss.type == N_FUN && ss.name == nil)
285 break;
286 if(ss.type == N_SLINE){
287 if(basepc+ss.value > pc)
288 break;
289 else
290 line = ss.desc;
293 *pline = line;
294 if(s->u.stabs.dir)
295 snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file);
296 else
297 snprint(buf, nbuf, "%s", s->u.stabs.file);
298 return 0;
301 static int
302 stabsline2pc(Fhdr *fhdr, u64int startpc, ulong line, u64int *pc)
304 int i, trigger;
305 Symbol *s;
306 StabSym ss;
307 ulong basepc;
308 Loc l;
310 l.type = LADDR;
311 l.addr = startpc;
312 if((s = ffindsym(fhdr, l, CTEXT)) == nil
313 || stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
314 return -1;
316 trigger = 0;
317 line = ss.desc;
318 basepc = ss.value;
319 for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
320 if(ss.type == N_FUN)
321 basepc = ss.value;
322 if(ss.type == N_SLINE){
323 if(basepc+ss.value >= startpc)
324 trigger = 1;
325 if(trigger && ss.desc >= line){
326 *pc = basepc+ss.value;
327 return 0;
331 return -1;
334 static int
335 stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
337 int i;
338 StabSym ss;
340 for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){
341 if(ss.type == N_FUN && ss.name == nil)
342 break;
343 switch(ss.type){
344 case N_PSYM:
345 case N_LSYM:
346 case N_LCSYM:
347 if(name){
348 if(strcmpcolon(name, ss.name) != 0)
349 break;
350 }else if(l.type){
351 /* wait for now */
352 }else{
353 if(j-- > 0)
354 break;
356 if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0)
357 return -1;
358 if(s->loc.type == LOFFSET){
359 if(p->u.stabs.frameptr == 0)
360 s->loc.reg = mach->sp;
361 else
362 s->loc.reg = mach->fp;
364 if(l.type && loccmp(&l, &s->loc) != 0)
365 break;
366 return 0;
369 return -1;
372 static Loc zl;
374 static int
375 stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
377 return stabslenum(fhdr, p, name, 0, zl, s);
380 static int
381 stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
383 return stabslenum(fhdr, p, nil, i, zl, s);
386 static int
387 stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
389 return stabslenum(fhdr, p, nil, 0, l, s);
392 int
393 symstabs(Fhdr *fp)
395 if(stabssyminit(fp) < 0)
396 return -1;
397 fp->pc2file = stabspc2file;
398 fp->line2pc = stabsline2pc;
399 fp->lookuplsym = stabslookuplsym;
400 fp->indexlsym = stabsindexlsym;
401 fp->findlsym = stabsfindlsym;
402 return 0;