aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/dwarfdump.c
blob: 1bb0507324251abd33307e3bd2981aa64f22c772 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#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);
	}
}