1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package dwarf
6
7import (
8	"sort"
9	"strconv"
10)
11
12// DWARF debug info is split into a sequence of compilation units.
13// Each unit has its own abbreviation table and address size.
14
15type unit struct {
16	base   Offset // byte offset of header within the aggregate info
17	off    Offset // byte offset of data within the aggregate info
18	data   []byte
19	atable abbrevTable
20	asize  int
21	vers   int
22	utype  uint8 // DWARF 5 unit type
23	is64   bool  // True for 64-bit DWARF format
24}
25
26// Implement the dataFormat interface.
27
28func (u *unit) version() int {
29	return u.vers
30}
31
32func (u *unit) dwarf64() (bool, bool) {
33	return u.is64, true
34}
35
36func (u *unit) addrsize() int {
37	return u.asize
38}
39
40func (d *Data) parseUnits() ([]unit, error) {
41	// Count units.
42	nunit := 0
43	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
44	for len(b.data) > 0 {
45		len, _ := b.unitLength()
46		if len != Offset(uint32(len)) {
47			b.error("unit length overflow")
48			break
49		}
50		b.skip(int(len))
51		if len > 0 {
52			nunit++
53		}
54	}
55	if b.err != nil {
56		return nil, b.err
57	}
58
59	// Again, this time writing them down.
60	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
61	units := make([]unit, nunit)
62	for i := range units {
63		u := &units[i]
64		u.base = b.off
65		var n Offset
66		if b.err != nil {
67			return nil, b.err
68		}
69		for n == 0 {
70			n, u.is64 = b.unitLength()
71		}
72		dataOff := b.off
73		vers := b.uint16()
74		if vers < 2 || vers > 5 {
75			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
76			break
77		}
78		u.vers = int(vers)
79		if vers >= 5 {
80			u.utype = b.uint8()
81			u.asize = int(b.uint8())
82		}
83		var abbrevOff uint64
84		if u.is64 {
85			abbrevOff = b.uint64()
86		} else {
87			abbrevOff = uint64(b.uint32())
88		}
89		atable, err := d.parseAbbrev(abbrevOff, u.vers)
90		if err != nil {
91			if b.err == nil {
92				b.err = err
93			}
94			break
95		}
96		u.atable = atable
97		if vers < 5 {
98			u.asize = int(b.uint8())
99		}
100
101		switch u.utype {
102		case utSkeleton, utSplitCompile:
103			b.uint64() // unit ID
104		case utType, utSplitType:
105			b.uint64()  // type signature
106			if u.is64 { // type offset
107				b.uint64()
108			} else {
109				b.uint32()
110			}
111		}
112
113		u.off = b.off
114		u.data = b.bytes(int(n - (b.off - dataOff)))
115	}
116	if b.err != nil {
117		return nil, b.err
118	}
119	return units, nil
120}
121
122// offsetToUnit returns the index of the unit containing offset off.
123// It returns -1 if no unit contains this offset.
124func (d *Data) offsetToUnit(off Offset) int {
125	// Find the unit after off
126	next := sort.Search(len(d.unit), func(i int) bool {
127		return d.unit[i].off > off
128	})
129	if next == 0 {
130		return -1
131	}
132	u := &d.unit[next-1]
133	if u.off <= off && off < u.off+Offset(len(u.data)) {
134		return next - 1
135	}
136	return -1
137}
138