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