Source file src/debug/dwarf/open.go

     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  /*
     6  Package dwarf provides access to DWARF debugging information loaded from
     7  executable files, as defined in the DWARF 2.0 Standard at
     8  http://dwarfstd.org/doc/dwarf-2.0.0.pdf.
     9  
    10  # Security
    11  
    12  This package is not designed to be hardened against adversarial inputs, and is
    13  outside the scope of https://go.dev/security/policy. In particular, only basic
    14  validation is done when parsing object files. As such, care should be taken when
    15  parsing untrusted inputs, as parsing malformed files may consume significant
    16  resources, or cause panics.
    17  */
    18  package dwarf
    19  
    20  import (
    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).
    27  type 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  
    53  var 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.
    63  func 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.
   118  func (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.
   126  func (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  

View as plain text