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		nunit++
52	}
53	if b.err != nil {
54		return nil, b.err
55	}
56
57	// Again, this time writing them down.
58	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
59	units := make([]unit, nunit)
60	for i := range units {
61		u := &units[i]
62		u.base = b.off
63		var n Offset
64		n, u.is64 = b.unitLength()
65		dataOff := b.off
66		vers := b.uint16()
67		if vers < 2 || vers > 5 {
68			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
69			break
70		}
71		u.vers = int(vers)
72		if vers >= 5 {
73			u.utype = b.uint8()
74			u.asize = int(b.uint8())
75		}
76		var abbrevOff uint64
77		if u.is64 {
78			abbrevOff = b.uint64()
79		} else {
80			abbrevOff = uint64(b.uint32())
81		}
82		atable, err := d.parseAbbrev(abbrevOff, u.vers)
83		if err != nil {
84			if b.err == nil {
85				b.err = err
86			}
87			break
88		}
89		u.atable = atable
90		if vers < 5 {
91			u.asize = int(b.uint8())
92		}
93
94		switch u.utype {
95		case utSkeleton, utSplitCompile:
96			b.uint64() // unit ID
97		case utType, utSplitType:
98			b.uint64()  // type signature
99			if u.is64 { // type offset
100				b.uint64()
101			} else {
102				b.uint32()
103			}
104		}
105
106		u.off = b.off
107		u.data = b.bytes(int(n - (b.off - dataOff)))
108	}
109	if b.err != nil {
110		return nil, b.err
111	}
112	return units, nil
113}
114
115// offsetToUnit returns the index of the unit containing offset off.
116// It returns -1 if no unit contains this offset.
117func (d *Data) offsetToUnit(off Offset) int {
118	// Find the unit after off
119	next := sort.Search(len(d.unit), func(i int) bool {
120		return d.unit[i].off > off
121	})
122	if next == 0 {
123		return -1
124	}
125	u := &d.unit[next-1]
126	if u.off <= off && off < u.off+Offset(len(u.data)) {
127		return next - 1
128	}
129	return -1
130}
131