| #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 | 
 | 					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); | 
 | 	} | 
 | } |