Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #include "elf.h"
6 #include "dwarf.h"
8 static void dwarfsymclose(Fhdr*);
9 static int dwarfpc2file(Fhdr*, u64int, char*, uint, ulong*);
10 static int dwarfline2pc(Fhdr*, u64int, ulong, u64int*);
11 static int dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
12 static int dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
13 static int dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
14 static void dwarfsyminit(Fhdr*);
15 static int dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
16 static int _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol*);
18 int
19 symdwarf(Fhdr *hdr)
20 {
21 if(hdr->dwarf == nil){
22 werrstr("no dwarf debugging symbols");
23 return -1;
24 }
26 hdr->symclose = dwarfsymclose;
27 hdr->pc2file = dwarfpc2file;
28 hdr->line2pc = dwarfline2pc;
29 hdr->lookuplsym = dwarflookuplsym;
30 hdr->indexlsym = dwarfindexlsym;
31 hdr->findlsym = dwarffindlsym;
32 hdr->unwind = _dwarfunwind;
33 dwarfsyminit(hdr);
35 return 0;
36 }
38 static void
39 dwarfsymclose(Fhdr *hdr)
40 {
41 dwarfclose(hdr->dwarf);
42 hdr->dwarf = nil;
43 }
45 static int
46 dwarfpc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *line)
47 {
48 char *cdir, *dir, *file;
50 if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
51 return -1;
53 if(file[0] == '/' || (dir==nil && cdir==nil))
54 strecpy(buf, buf+nbuf, file);
55 else if((dir && dir[0] == '/') || cdir==nil)
56 snprint(buf, nbuf, "%s/%s", dir, file);
57 else
58 snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
59 cleanname(buf);
60 return 0;;
61 }
63 static int
64 dwarfline2pc(Fhdr *fhdr, u64int basepc, ulong line, u64int *pc)
65 {
66 werrstr("dwarf line2pc not implemented");
67 return -1;
68 }
70 static uint
71 typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
72 {
73 DwarfSym ds;
75 top:
76 if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
77 cannot:
78 fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
79 name, unit, tref);
80 return 0;
81 }
83 if(ds.attrs.have.bytesize)
84 return ds.attrs.bytesize;
86 switch(ds.attrs.tag){
87 case TagVolatileType:
88 case TagRestrictType:
89 case TagTypedef:
90 if(ds.attrs.have.type != TReference)
91 goto cannot;
92 tref = ds.attrs.type;
93 goto top;
94 }
96 goto cannot;
97 }
99 static int
100 roundup(int s, int n)
102 return (s+n-1)&~(n-1);
105 static int
106 dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
108 int depth, bpoff;
109 DwarfSym ds;
110 Symbol s1;
112 if(p == nil)
113 return -1;
115 if(p->u.dwarf.unit == 0 && p->u.dwarf.uoff == 0)
116 return -1;
118 if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
119 return -1;
121 ds.depth = 1;
122 depth = 1;
124 bpoff = 8;
125 while(dwarfnextsym(fhdr->dwarf, &ds) == 1 && depth < ds.depth){
126 if(ds.attrs.tag != TagVariable){
127 if(ds.attrs.tag != TagFormalParameter
128 && ds.attrs.tag != TagUnspecifiedParameters)
129 continue;
130 if(ds.depth != depth+1)
131 continue;
133 if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
134 continue;
135 /* XXX move this out once there is another architecture */
136 /*
137 * gcc tells us the registers where the parameters might be
138 * held for an instruction or two. use the parameter list to
139 * recompute the actual stack locations.
140 */
141 if(fhdr->mtype == M386)
142 if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
143 if(s1.loc.type==LOFFSET
144 && strcmp(s1.loc.reg, "BP")==0
145 && s1.loc.offset >= 8)
146 bpoff = s1.loc.offset;
147 else{
148 s1.loc.type = LOFFSET;
149 s1.loc.reg = "BP";
150 s1.loc.offset = bpoff;
152 if(ds.attrs.tag == TagFormalParameter){
153 if(ds.attrs.have.type)
154 bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
155 else
156 fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
159 if(name){
160 if(strcmp(ds.attrs.name, name) != 0)
161 continue;
162 }else if(l.type){
163 if(loccmp(&s1.loc, &l) != 0)
164 continue;
165 }else{
166 if(j-- > 0)
167 continue;
169 *s = s1;
170 return 0;
172 return -1;
175 static Loc zl;
177 static int
178 dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
180 return dwarflenum(fhdr, p, name, 0, zl, s);
183 static int
184 dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
186 return dwarflenum(fhdr, p, nil, i, zl, s);
189 static int
190 dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
192 return dwarflenum(fhdr, p, nil, 0, l, s);
195 static void
196 dwarfsyminit(Fhdr *fp)
198 Dwarf *d;
199 DwarfSym s;
200 Symbol sym;
202 d = fp->dwarf;
203 if(dwarfenum(d, &s) < 0)
204 return;
206 while(dwarfnextsymat(d, &s, 0) == 1)
207 while(dwarfnextsymat(d, &s, 1) == 1){
208 if(s.attrs.name == nil)
209 continue;
210 switch(s.attrs.tag){
211 case TagSubprogram:
212 case TagVariable:
213 if(dwarftosym(fp, d, &s, &sym, 0) < 0)
214 continue;
215 _addsym(fp, &sym);
220 static char*
221 regname(Dwarf *d, int i)
223 if(i < 0 || i >= d->nreg)
224 return nil;
225 return d->reg[i];
228 static int
229 dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
231 DwarfBuf buf;
232 DwarfBlock b;
234 memset(s, 0, sizeof *s);
235 s->u.dwarf.uoff = ds->uoff;
236 s->u.dwarf.unit = ds->unit;
237 switch(ds->attrs.tag){
238 default:
239 return -1;
240 case TagUnspecifiedParameters:
241 ds->attrs.name = "...";
242 s->type = 'p';
243 goto sym;
244 case TagFormalParameter:
245 s->type = 'p';
246 s->class = CPARAM;
247 goto sym;
248 case TagSubprogram:
249 s->type = 't';
250 s->class = CTEXT;
251 goto sym;
252 case TagVariable:
253 if(infn){
254 s->type = 'a';
255 s->class = CAUTO;
256 }else{
257 s->type = 'd';
258 s->class = CDATA;
260 sym:
261 s->name = ds->attrs.name;
262 if(ds->attrs.have.lowpc){
263 s->loc.type = LADDR;
264 s->loc.addr = ds->attrs.lowpc;
265 if(ds->attrs.have.highpc){
266 s->hiloc.type = LADDR;
267 s->hiloc.addr = ds->attrs.highpc;
269 }else if(ds->attrs.have.location == TConstant){
270 s->loc.type = LADDR;
271 s->loc.addr = ds->attrs.location.c;
272 }else if(ds->attrs.have.location == TBlock){
273 b = ds->attrs.location.b;
274 if(b.len == 0)
275 return -1;
276 buf.p = b.data+1;
277 buf.ep = b.data+b.len;
278 buf.d = d;
279 buf.addrsize = 0;
280 if(b.data[0]==OpAddr){
281 if(b.len != 5)
282 return -1;
283 s->loc.type = LADDR;
284 s->loc.addr = dwarfgetaddr(&buf);
285 }else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
286 if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
287 return -1;
288 s->loc.type = LREG;
289 }else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
290 s->loc.type = LOFFSET;
291 s->loc.reg = regname(d, b.data[0]-0x70);
292 s->loc.offset = dwarfget128s(&buf);
293 if(s->loc.reg == nil)
294 return -1;
295 }else if(b.data[0] == OpRegx){
296 s->loc.type = LREG;
297 s->loc.reg = regname(d, dwarfget128(&buf));
298 if(s->loc.reg == nil)
299 return -1;
300 }else if(b.data[0] == OpFbreg){
301 s->loc.type = LOFFSET;
302 s->loc.reg = mach->fp;
303 s->loc.offset = dwarfget128s(&buf);
304 }else if(b.data[0] == OpBregx){
305 s->loc.type = LOFFSET;
306 s->loc.reg = regname(d, dwarfget128(&buf));
307 s->loc.offset = dwarfget128s(&buf);
308 if(s->loc.reg == nil)
309 return -1;
310 }else
311 s->loc.type = LNONE;
312 if(buf.p != buf.ep)
313 s->loc.type = LNONE;
314 }else
315 return -1;
316 if(ds->attrs.isexternal)
317 s->type += 'A' - 'a';
318 if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
319 s->type += 'b' - 'd';
320 s->fhdr = fp;
321 return 0;
325 static int
326 dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, u64int *u)
328 int i;
329 u32int u4;
330 u64int uu;
332 switch(e.type){
333 case RuleUndef:
334 *u = 0;
335 return 0;
336 case RuleSame:
337 if(rno == -1){
338 werrstr("pc cannot be `same'");
339 return -1;
341 return rget(regs, regname(d, rno), u);
342 case RuleRegister:
343 if((i = windindex(regname(d, e.reg))) < 0)
344 return -1;
345 return rget(regs, regname(d, i), u);
346 case RuleCfaOffset:
347 if(cfa == 0){
348 werrstr("unknown cfa");
349 return -1;
351 if(get4(map, cfa + e.offset, &u4) < 0)
352 return -1;
353 *u = u4;
354 return 0;
355 case RuleRegOff:
356 if(rget(regs, regname(d, e.reg), &uu) < 0)
357 return -1;
358 if(get4(map, uu+e.offset, &u4) < 0)
359 return -1;
360 *u = u4;
361 return 0;
362 case RuleLocation:
363 werrstr("not evaluating dwarf loc expressions");
364 return -1;
366 werrstr("not reached in dwarfeval");
367 return -1;
370 #if 0
371 static int
372 dwarfexprfmt(Fmt *fmt)
374 DwarfExpr *e;
376 if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
377 return fmtstrcpy(fmt, "<nil>");
379 switch(e->type){
380 case RuleUndef:
381 return fmtstrcpy(fmt, "undef");
382 case RuleSame:
383 return fmtstrcpy(fmt, "same");
384 case RuleCfaOffset:
385 return fmtprint(fmt, "%ld(cfa)", e->offset);
386 case RuleRegister:
387 return fmtprint(fmt, "r%ld", e->reg);
388 case RuleRegOff:
389 return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
390 case RuleLocation:
391 return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
392 default:
393 return fmtprint(fmt, "?%d", e->type);
396 #endif
398 static int
399 _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol *sym)
401 char *name;
402 int i, j;
403 u64int cfa, pc, u;
404 Dwarf *d;
405 DwarfExpr *e, epc, ecfa;
408 /*
409 * Use dwarfunwind to tell us what to do.
410 */
411 d = fhdr->dwarf;
412 e = malloc(d->nreg*sizeof(e[0]));
413 if(e == nil)
414 return -1;
415 if(rget(regs, mach->pc, &pc) < 0)
416 goto err;
417 if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
418 goto err;
420 /*
421 * Compute CFA.
422 */
423 switch(ecfa.type){
424 default:
425 werrstr("invalid call-frame-address in _dwarfunwind");
426 goto err;
427 case RuleRegister:
428 ecfa.offset = 0;
429 case RuleRegOff:
430 if((name = regname(d, ecfa.reg)) == nil){
431 werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
432 goto err;
434 if(rget(regs, name, &cfa) < 0){
435 werrstr("fetching %s for call-frame-address: %r", name);
436 goto err;
438 cfa += ecfa.offset;
441 /*
442 * Compute registers.
443 */
444 for(i=0; i<d->nreg; i++){
445 j = windindex(d->reg[i]);
446 if(j == -1)
447 continue;
448 if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
449 u = ~(ulong)0;
450 next[j] = u;
453 /*
454 * Compute caller pc
455 */
456 if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
457 werrstr("computing caller %s: %r", mach->pc);
458 goto err;
460 next[windindex(mach->pc)] = u;
461 free(e);
462 return 0;
464 err:
465 free(e);
466 return -1;