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
5/*
6Package dwarf provides access to DWARF debugging information loaded from
7executable files, as defined in the DWARF 2.0 Standard at
8http://dwarfstd.org/doc/dwarf-2.0.0.pdf.
9
10# Security
11
12This package is not designed to be hardened against adversarial inputs, and is
13outside the scope of https://go.dev/security/policy. In particular, only basic
14validation is done when parsing object files. As such, care should be taken when
15parsing untrusted inputs, as parsing malformed files may consume significant
16resources, or cause panics.
17*/
18package dwarf
19
20import (
21	"encoding/binary"
22	"errors"
23)
24
25// Data represents the DWARF debugging information
26// loaded from an executable file (for example, an ELF or Mach-O executable).
27type Data struct {
28	// raw data
29	abbrev   []byte
30	aranges  []byte
31	frame    []byte
32	info     []byte
33	line     []byte
34	pubnames []byte
35	ranges   []byte
36	str      []byte
37
38	// New sections added in DWARF 5.
39	addr       []byte
40	lineStr    []byte
41	strOffsets []byte
42	rngLists   []byte
43
44	// parsed data
45	abbrevCache map[uint64]abbrevTable
46	bigEndian   bool
47	order       binary.ByteOrder
48	typeCache   map[Offset]Type
49	typeSigs    map[uint64]*typeUnit
50	unit        []unit
51}
52
53var errSegmentSelector = errors.New("non-zero segment_selector size not supported")
54
55// New returns a new [Data] object initialized from the given parameters.
56// Rather than calling this function directly, clients should typically use
57// the DWARF method of the File type of the appropriate package [debug/elf],
58// [debug/macho], or [debug/pe].
59//
60// The []byte arguments are the data from the corresponding debug section
61// in the object file; for example, for an ELF object, abbrev is the contents of
62// the ".debug_abbrev" section.
63func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Data, error) {
64	d := &Data{
65		abbrev:      abbrev,
66		aranges:     aranges,
67		frame:       frame,
68		info:        info,
69		line:        line,
70		pubnames:    pubnames,
71		ranges:      ranges,
72		str:         str,
73		abbrevCache: make(map[uint64]abbrevTable),
74		typeCache:   make(map[Offset]Type),
75		typeSigs:    make(map[uint64]*typeUnit),
76	}
77
78	// Sniff .debug_info to figure out byte order.
79	// 32-bit DWARF: 4 byte length, 2 byte version.
80	// 64-bit DWARf: 4 bytes of 0xff, 8 byte length, 2 byte version.
81	if len(d.info) < 6 {
82		return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
83	}
84	offset := 4
85	if d.info[0] == 0xff && d.info[1] == 0xff && d.info[2] == 0xff && d.info[3] == 0xff {
86		if len(d.info) < 14 {
87			return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
88		}
89		offset = 12
90	}
91	// Fetch the version, a tiny 16-bit number (1, 2, 3, 4, 5).
92	x, y := d.info[offset], d.info[offset+1]
93	switch {
94	case x == 0 && y == 0:
95		return nil, DecodeError{"info", 4, "unsupported version 0"}
96	case x == 0:
97		d.bigEndian = true
98		d.order = binary.BigEndian
99	case y == 0:
100		d.bigEndian = false
101		d.order = binary.LittleEndian
102	default:
103		return nil, DecodeError{"info", 4, "cannot determine byte order"}
104	}
105
106	u, err := d.parseUnits()
107	if err != nil {
108		return nil, err
109	}
110	d.unit = u
111	return d, nil
112}
113
114// AddTypes will add one .debug_types section to the DWARF data. A
115// typical object with DWARF version 4 debug info will have multiple
116// .debug_types sections. The name is used for error reporting only,
117// and serves to distinguish one .debug_types section from another.
118func (d *Data) AddTypes(name string, types []byte) error {
119	return d.parseTypes(name, types)
120}
121
122// AddSection adds another DWARF section by name. The name should be a
123// DWARF section name such as ".debug_addr", ".debug_str_offsets", and
124// so forth. This approach is used for new DWARF sections added in
125// DWARF 5 and later.
126func (d *Data) AddSection(name string, contents []byte) error {
127	var err error
128	switch name {
129	case ".debug_addr":
130		d.addr = contents
131	case ".debug_line_str":
132		d.lineStr = contents
133	case ".debug_str_offsets":
134		d.strOffsets = contents
135	case ".debug_rnglists":
136		d.rngLists = contents
137	}
138	// Just ignore names that we don't yet support.
139	return err
140}
141