aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/dwarfabbrev.c
blob: 2db418ddb852364c99e64ed1029145c7ad9e62dc (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
/*
 * Dwarf abbreviation parsing code.
 *
 * The convention here is that calling dwarfgetabbrevs relinquishes
 * access to any abbrevs returned previously.  Will have to add 
 * explicit reference counting if this turns out not to be acceptable.
 */

#include <u.h>
#include <libc.h>
#include <bio.h>
#include "elf.h"
#include "dwarf.h"

static int parseabbrevs(Dwarf*, ulong, DwarfAbbrev*, DwarfAttr*, int*, int*);
DwarfAbbrev *dwarfgetabbrev(Dwarf*, ulong, ulong);

static int
loadabbrevs(Dwarf *d, ulong off, DwarfAbbrev **aa)
{
	int nattr, nabbrev;
	DwarfAbbrev *abbrev;
	DwarfAttr *attr;

	if(d->acache.off == off && d->acache.na){
		*aa = d->acache.a;
		return d->acache.na;
	}

	/* two passes - once to count, then allocate, then a second to copy */
	if(parseabbrevs(d, off, nil, nil, &nabbrev, &nattr) < 0)
		return -1;

	abbrev = malloc(nabbrev*sizeof(DwarfAbbrev) + nattr*sizeof(DwarfAttr));
	attr = (DwarfAttr*)(abbrev+nabbrev);

	if(parseabbrevs(d, off, abbrev, attr, nil, nil) < 0){
		free(abbrev);
		return -1;
	}

	free(d->acache.a);
	d->acache.a = abbrev;
	d->acache.na = nabbrev;
	d->acache.off = off;

	*aa = abbrev;
	return nabbrev;
}

static int
parseabbrevs(Dwarf *d, ulong off, DwarfAbbrev *abbrev, DwarfAttr *attr, int *pnabbrev, int *pnattr)
{
	int i, nabbrev, nattr, haskids;
	ulong num, tag, name, form;
	DwarfBuf b;

	if(off >= d->abbrev.len){
		werrstr("bad abbrev section offset 0x%lux >= 0x%lux\n", off, d->abbrev.len);
		return -1;
	}

	memset(&b, 0, sizeof b);
	b.p = d->abbrev.data + off;
	b.ep = d->abbrev.data + d->abbrev.len;

	nabbrev = 0;
	nattr = 0;
	for(;;){
		if(b.p == nil){
			werrstr("malformed abbrev data");
			return -1;
		}
		num = dwarfget128(&b);
		if(num == 0)
			break;
		tag = dwarfget128(&b);
		haskids = dwarfget1(&b);
		for(i=0;; i++){
			name = dwarfget128(&b);
			form = dwarfget128(&b);
			if(name == 0 && form == 0)
				break;
			if(attr){
				attr[i].name = name;
				attr[i].form = form;
			}
		}
		if(abbrev){
			abbrev->num = num;
			abbrev->tag = tag;
			abbrev->haskids = haskids;
			abbrev->attr = attr;
			abbrev->nattr = i;
			abbrev++;
			attr += i;
		}
		nabbrev++;
		nattr += i;
	}
	if(pnabbrev)
		*pnabbrev = nabbrev;
	if(pnattr)
		*pnattr = nattr;
	return 0;
}

static DwarfAbbrev*
findabbrev(DwarfAbbrev *a, int na, ulong num)
{
	int i;

	for(i=0; i<na; i++)
		if(a[i].num == num)
			return &a[i];
	return nil;
}

DwarfAbbrev*
dwarfgetabbrev(Dwarf *d, ulong off, ulong num)
{
	DwarfAbbrev *a;
	int na;

	if((na = loadabbrevs(d, off, &a)) < 0)
		return nil;
	return findabbrev(a, na, num);
}