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	is64   bool // True for 64-bit DWARF format
23}
24
25// Implement the dataFormat interface.
26
27func (u *unit) version() int {
28	return u.vers
29}
30
31func (u *unit) dwarf64() (bool, bool) {
32	return u.is64, true
33}
34
35func (u *unit) addrsize() int {
36	return u.asize
37}
38
39func (d *Data) parseUnits() ([]unit, error) {
40	// Count units.
41	nunit := 0
42	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
43	for len(b.data) > 0 {
44		len, _ := b.unitLength()
45		if len != Offset(uint32(len)) {
46			b.error("unit length overflow")
47			break
48		}
49		b.skip(int(len))
50		nunit++
51	}
52	if b.err != nil {
53		return nil, b.err
54	}
55
56	// Again, this time writing them down.
57	b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
58	units := make([]unit, nunit)
59	for i := range units {
60		u := &units[i]
61		u.base = b.off
62		var n Offset
63		n, u.is64 = b.unitLength()
64		vers := b.uint16()
65		if vers != 2 && vers != 3 && vers != 4 {
66			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
67			break
68		}
69		u.vers = int(vers)
70		atable, err := d.parseAbbrev(b.uint32(), u.vers)
71		if err != nil {
72			if b.err == nil {
73				b.err = err
74			}
75			break
76		}
77		u.atable = atable
78		u.asize = int(b.uint8())
79		u.off = b.off
80		u.data = b.bytes(int(n - (2 + 4 + 1)))
81	}
82	if b.err != nil {
83		return nil, b.err
84	}
85	return units, nil
86}
87
88// offsetToUnit returns the index of the unit containing offset off.
89// It returns -1 if no unit contains this offset.
90func (d *Data) offsetToUnit(off Offset) int {
91	// Find the unit after off
92	next := sort.Search(len(d.unit), func(i int) bool {
93		return d.unit[i].off > off
94	})
95	if next == 0 {
96		return -1
97	}
98	u := &d.unit[next-1]
99	if u.off <= off && off < u.off+Offset(len(u.data)) {
100		return next - 1
101	}
102	return -1
103}
104