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*, ulong, char*, uint, ulong*);
10 static int dwarfline2pc(Fhdr*, ulong, ulong, ulong*);
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, ulong *next);
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, ulong 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, ulong basepc, ulong line, ulong *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(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
116 return -1;
118 ds.depth = 1;
119 depth = 1;
121 bpoff = 8;
122 while(dwarfnextsym(fhdr->dwarf, &ds, 1) == 1 && depth < ds.depth){
123 if(ds.attrs.tag != TagVariable){
124 if(ds.attrs.tag != TagFormalParameter
125 && ds.attrs.tag != TagUnspecifiedParameters)
126 continue;
127 if(ds.depth != depth+1)
128 continue;
130 if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
131 continue;
132 /* XXX move this out once there is another architecture */
133 /*
134 * gcc tells us the registers where the parameters might be
135 * held for an instruction or two. use the parameter list to
136 * recompute the actual stack locations.
137 */
138 if(fhdr->mtype == M386)
139 if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
140 if(s1.loc.type==LOFFSET
141 && strcmp(s1.loc.reg, "BP")==0
142 && s1.loc.offset >= 8)
143 bpoff = s1.loc.offset;
144 else{
145 s1.loc.type = LOFFSET;
146 s1.loc.reg = "BP";
147 s1.loc.offset = bpoff;
149 if(ds.attrs.tag == TagFormalParameter){
150 if(ds.attrs.have.type)
151 bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
152 else
153 fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
156 if(name){
157 if(strcmp(ds.attrs.name, name) != 0)
158 continue;
159 }else if(l.type){
160 if(loccmp(&s1.loc, &l) != 0)
161 continue;
162 }else{
163 if(j-- > 0)
164 continue;
166 *s = s1;
167 return 0;
169 return -1;
172 static Loc zl;
174 static int
175 dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
177 return dwarflenum(fhdr, p, name, 0, zl, s);
180 static int
181 dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
183 return dwarflenum(fhdr, p, nil, i, zl, s);
186 static int
187 dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
189 return dwarflenum(fhdr, p, nil, 0, l, s);
192 static void
193 dwarfsyminit(Fhdr *fp)
195 Dwarf *d;
196 DwarfSym s;
197 Symbol sym;
199 d = fp->dwarf;
200 if(dwarfenum(d, &s) < 0)
201 return;
203 while(dwarfnextsym(d, &s, s.depth!=1) == 1){
204 if(s.depth != 1)
205 continue;
206 if(s.attrs.name == nil)
207 continue;
208 switch(s.attrs.tag){
209 case TagSubprogram:
210 case TagVariable:
211 if(dwarftosym(fp, d, &s, &sym, 0) < 0)
212 continue;
213 addsym(fp, &sym);
218 static char*
219 regname(Dwarf *d, int i)
221 if(i < 0 || i >= d->nreg)
222 return nil;
223 return d->reg[i];
226 static int
227 dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
229 DwarfBuf buf;
230 DwarfBlock b;
232 memset(s, 0, sizeof *s);
233 s->u.dwarf.uoff = ds->uoff;
234 s->u.dwarf.unit = ds->unit;
235 switch(ds->attrs.tag){
236 default:
237 return -1;
238 case TagUnspecifiedParameters:
239 ds->attrs.name = "...";
240 s->type = 'p';
241 goto sym;
242 case TagFormalParameter:
243 s->type = 'p';
244 s->class = CPARAM;
245 goto sym;
246 case TagSubprogram:
247 s->type = 't';
248 s->class = CTEXT;
249 goto sym;
250 case TagVariable:
251 if(infn){
252 s->type = 'a';
253 s->class = CAUTO;
254 }else{
255 s->type = 'd';
256 s->class = CDATA;
258 sym:
259 s->name = ds->attrs.name;
260 if(ds->attrs.have.lowpc){
261 s->loc.type = LADDR;
262 s->loc.addr = ds->attrs.lowpc;
263 if(ds->attrs.have.highpc){
264 s->hiloc.type = LADDR;
265 s->hiloc.addr = ds->attrs.highpc;
267 }else if(ds->attrs.have.location == TConstant){
268 s->loc.type = LADDR;
269 s->loc.addr = ds->attrs.location.c;
270 }else if(ds->attrs.have.location == TBlock){
271 b = ds->attrs.location.b;
272 if(b.len == 0)
273 return -1;
274 buf.p = b.data+1;
275 buf.ep = b.data+b.len;
276 buf.d = d;
277 buf.addrsize = 0;
278 if(b.data[0]==OpAddr){
279 if(b.len != 5)
280 return -1;
281 s->loc.type = LADDR;
282 s->loc.addr = dwarfgetaddr(&buf);
283 }else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
284 if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
285 return -1;
286 s->loc.type = LREG;
287 }else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
288 s->loc.type = LOFFSET;
289 s->loc.reg = regname(d, b.data[0]-0x70);
290 s->loc.offset = dwarfget128s(&buf);
291 if(s->loc.reg == nil)
292 return -1;
293 }else if(b.data[0] == OpRegx){
294 s->loc.type = LREG;
295 s->loc.reg = regname(d, dwarfget128(&buf));
296 if(s->loc.reg == nil)
297 return -1;
298 }else if(b.data[0] == OpFbreg){
299 s->loc.type = LOFFSET;
300 s->loc.reg = mach->fp;
301 s->loc.offset = dwarfget128s(&buf);
302 }else if(b.data[0] == OpBregx){
303 s->loc.type = LOFFSET;
304 s->loc.reg = regname(d, dwarfget128(&buf));
305 s->loc.offset = dwarfget128s(&buf);
306 if(s->loc.reg == nil)
307 return -1;
308 }else
309 s->loc.type = LNONE;
310 if(buf.p != buf.ep)
311 s->loc.type = LNONE;
312 }else
313 return -1;
314 if(ds->attrs.isexternal)
315 s->type += 'A' - 'a';
316 if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
317 s->type += 'b' - 'd';
318 s->fhdr = fp;
319 return 0;
323 static int
324 dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, ulong *u)
326 int i;
327 u32int u4;
328 ulong uu;
330 switch(e.type){
331 case RuleUndef:
332 *u = 0;
333 return 0;
334 case RuleSame:
335 if(rno == -1){
336 werrstr("pc cannot be `same'");
337 return -1;
339 return rget(regs, regname(d, rno), u);
340 case RuleRegister:
341 if((i = windindex(regname(d, e.reg))) < 0)
342 return -1;
343 return rget(regs, regname(d, i), u);
344 case RuleCfaOffset:
345 if(cfa == 0){
346 werrstr("unknown cfa");
347 return -1;
349 if(get4(map, cfa + e.offset, &u4) < 0)
350 return -1;
351 *u = u4;
352 return 0;
353 case RuleRegOff:
354 if(rget(regs, regname(d, e.reg), &uu) < 0)
355 return -1;
356 if(get4(map, uu+e.offset, &u4) < 0)
357 return -1;
358 *u = u4;
359 return 0;
360 case RuleLocation:
361 werrstr("not evaluating dwarf loc expressions");
362 return -1;
364 werrstr("not reached in dwarfeval");
365 return -1;
368 #if 0
369 static int
370 dwarfexprfmt(Fmt *fmt)
372 DwarfExpr *e;
374 if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
375 return fmtstrcpy(fmt, "<nil>");
377 switch(e->type){
378 case RuleUndef:
379 return fmtstrcpy(fmt, "undef");
380 case RuleSame:
381 return fmtstrcpy(fmt, "same");
382 case RuleCfaOffset:
383 return fmtprint(fmt, "%ld(cfa)", e->offset);
384 case RuleRegister:
385 return fmtprint(fmt, "r%ld", e->reg);
386 case RuleRegOff:
387 return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
388 case RuleLocation:
389 return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
390 default:
391 return fmtprint(fmt, "?%d", e->type);
394 #endif
396 static int
397 _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, ulong *next)
399 char *name;
400 int i, j;
401 ulong cfa, pc, u;
402 Dwarf *d;
403 DwarfExpr *e, epc, ecfa;
406 /*
407 * Use dwarfunwind to tell us what to do.
408 */
409 d = fhdr->dwarf;
410 e = malloc(d->nreg*sizeof(e[0]));
411 if(e == nil)
412 return -1;
413 if(rget(regs, mach->pc, &pc) < 0)
414 goto err;
415 if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
416 goto err;
418 /*
419 * Compute CFA.
420 */
421 switch(ecfa.type){
422 default:
423 werrstr("invalid call-frame-address in _dwarfunwind");
424 goto err;
425 case RuleRegister:
426 ecfa.offset = 0;
427 case RuleRegOff:
428 if((name = regname(d, ecfa.reg)) == nil){
429 werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
430 goto err;
432 if(rget(regs, name, &cfa) < 0){
433 werrstr("fetching %s for call-frame-address: %r", name);
434 goto err;
436 cfa += ecfa.offset;
439 /*
440 * Compute registers.
441 */
442 for(i=0; i<d->nreg; i++){
443 j = windindex(d->reg[i]);
444 if(j == -1)
445 continue;
446 if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
447 u = ~(ulong)0;
448 next[j] = u;
451 /*
452 * Compute caller pc
453 */
454 if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
455 werrstr("computing caller %s: %r", mach->pc);
456 goto err;
458 next[windindex(mach->pc)] = u;
459 free(e);
460 return 0;
462 err:
463 free(e);
464 return -1;