| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include "elf.h" |
| #include "dwarf.h" |
| |
| void printrules(Dwarf *d, ulong pc); |
| int exprfmt(Fmt*); |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: dwarfdump file\n"); |
| exits("usage"); |
| } |
| |
| void |
| main(int argc, char **argv) |
| { |
| int c; |
| Elf *elf; |
| Dwarf *d; |
| DwarfSym s; |
| char *cdir, *dir, *file; |
| ulong line, mtime, length; |
| |
| ARGBEGIN{ |
| default: |
| usage(); |
| }ARGEND |
| |
| if(argc != 1) |
| usage(); |
| |
| fmtinstall('R', exprfmt); |
| fmtinstall('H', encodefmt); |
| |
| if((elf = elfopen(argv[0])) == nil) |
| sysfatal("elfopen %s: %r", argv[0]); |
| if((d=dwarfopen(elf)) == nil) |
| sysfatal("dwarfopen: %r"); |
| |
| if(dwarfenum(d, &s) < 0) |
| sysfatal("dwarfenumall: %r"); |
| |
| while(dwarfnextsym(d, &s) == 1){ |
| switch(s.attrs.tag){ |
| case TagCompileUnit: |
| print("compileunit %s\n", s.attrs.name); |
| break; |
| case TagSubprogram: |
| c = 't'; |
| goto sym; |
| case TagVariable: |
| c = 'd'; |
| goto sym; |
| case TagConstant: |
| c = 'c'; |
| goto sym; |
| case TagFormalParameter: |
| if(!s.attrs.name) |
| break; |
| c = 'p'; |
| sym: |
| if(s.attrs.isexternal) |
| c += 'A' - 'a'; |
| print("%c %s", c, s.attrs.name); |
| if(s.attrs.have.lowpc) |
| print(" 0x%lux-0x%lux", s.attrs.lowpc, s.attrs.highpc); |
| switch(s.attrs.have.location){ |
| case TBlock: |
| print(" @ %.*H", s.attrs.location.b.len, s.attrs.location.b.data); |
| break; |
| case TConstant: |
| print(" @ 0x%lux", s.attrs.location.c); |
| break; |
| } |
| if(s.attrs.have.ranges) |
| print(" ranges@0x%lux", s.attrs.ranges); |
| print("\n"); |
| if(s.attrs.have.lowpc){ |
| if(dwarfpctoline(d, s.attrs.lowpc, &cdir, &dir, &file, &line, &mtime, &length) < 0) |
| print("\tcould not find source: %r\n"); |
| else if(dir == nil) |
| print("\t%s/%s:%lud mtime=%lud length=%lud\n", |
| cdir, file, line, mtime, length); |
| else |
| print("\t%s/%s/%s:%lud mtime=%lud length=%lud\n", |
| cdir, dir, file, line, mtime, length); |
| |
| if(0) printrules(d, s.attrs.lowpc); |
| if(0) printrules(d, (s.attrs.lowpc+s.attrs.highpc)/2); |
| } |
| break; |
| } |
| } |
| exits(0); |
| } |
| |
| void |
| printrules(Dwarf *d, ulong pc) |
| { |
| int i; |
| DwarfExpr r[10]; |
| DwarfExpr cfa, ra; |
| |
| if(dwarfunwind(d, pc, &cfa, &ra, r, nelem(r)) < 0) |
| print("\tcannot unwind from pc 0x%lux: %r\n", pc); |
| |
| print("\tpc=0x%lux cfa=%R ra=%R", pc, &cfa, &ra); |
| for(i=0; i<nelem(r); i++) |
| if(r[i].type != RuleSame) |
| print(" r%d=%R", i, &r[i]); |
| print("\n"); |
| } |
| |
| int |
| exprfmt(Fmt *fmt) |
| { |
| DwarfExpr *e; |
| |
| if((e = va_arg(fmt->args, DwarfExpr*)) == nil) |
| return fmtstrcpy(fmt, "<nil>"); |
| |
| switch(e->type){ |
| case RuleUndef: |
| return fmtstrcpy(fmt, "undef"); |
| case RuleSame: |
| return fmtstrcpy(fmt, "same"); |
| case RuleCfaOffset: |
| return fmtprint(fmt, "%ld(cfa)", e->offset); |
| case RuleRegister: |
| return fmtprint(fmt, "r%ld", e->reg); |
| case RuleRegOff: |
| return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg); |
| case RuleLocation: |
| return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data); |
| default: |
| return fmtprint(fmt, "?%d", e->type); |
| } |
| } |