diff options
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/dwarf')
| -rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go | 1650 | ||||
| -rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go | 493 | 
2 files changed, 2143 insertions, 0 deletions
| diff --git a/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go new file mode 100644 index 000000000..2fee79d38 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf.go @@ -0,0 +1,1650 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package dwarf generates DWARF debugging information. +// DWARF generation is split between the compiler and the linker, +// this package contains the shared code. +package dwarf + +import ( +	"bytes" +	"github.com/twitchyliquid64/golang-asm/objabi" +	"errors" +	"fmt" +	"os/exec" +	"sort" +	"strconv" +	"strings" +) + +// InfoPrefix is the prefix for all the symbols containing DWARF info entries. +const InfoPrefix = "go.info." + +// ConstInfoPrefix is the prefix for all symbols containing DWARF info +// entries that contain constants. +const ConstInfoPrefix = "go.constinfo." + +// CUInfoPrefix is the prefix for symbols containing information to +// populate the DWARF compilation unit info entries. +const CUInfoPrefix = "go.cuinfo." + +// Used to form the symbol name assigned to the DWARF 'abstract subprogram" +// info entry for a function +const AbstractFuncSuffix = "$abstract" + +// Controls logging/debugging for selected aspects of DWARF subprogram +// generation (functions, scopes). +var logDwarf bool + +// Sym represents a symbol. +type Sym interface { +	Length(dwarfContext interface{}) int64 +} + +// A Var represents a local variable or a function parameter. +type Var struct { +	Name          string +	Abbrev        int // Either DW_ABRV_AUTO[_LOCLIST] or DW_ABRV_PARAM[_LOCLIST] +	IsReturnValue bool +	IsInlFormal   bool +	StackOffset   int32 +	// This package can't use the ssa package, so it can't mention ssa.FuncDebug, +	// so indirect through a closure. +	PutLocationList func(listSym, startPC Sym) +	Scope           int32 +	Type            Sym +	DeclFile        string +	DeclLine        uint +	DeclCol         uint +	InlIndex        int32 // subtract 1 to form real index into InlTree +	ChildIndex      int32 // child DIE index in abstract function +	IsInAbstract    bool  // variable exists in abstract function +} + +// A Scope represents a lexical scope. All variables declared within a +// scope will only be visible to instructions covered by the scope. +// Lexical scopes are contiguous in source files but can end up being +// compiled to discontiguous blocks of instructions in the executable. +// The Ranges field lists all the blocks of instructions that belong +// in this scope. +type Scope struct { +	Parent int32 +	Ranges []Range +	Vars   []*Var +} + +// A Range represents a half-open interval [Start, End). +type Range struct { +	Start, End int64 +} + +// This container is used by the PutFunc* variants below when +// creating the DWARF subprogram DIE(s) for a function. +type FnState struct { +	Name          string +	Importpath    string +	Info          Sym +	Filesym       Sym +	Loc           Sym +	Ranges        Sym +	Absfn         Sym +	StartPC       Sym +	Size          int64 +	External      bool +	Scopes        []Scope +	InlCalls      InlCalls +	UseBASEntries bool +} + +func EnableLogging(doit bool) { +	logDwarf = doit +} + +// UnifyRanges merges the list of ranges of c into the list of ranges of s +func (s *Scope) UnifyRanges(c *Scope) { +	out := make([]Range, 0, len(s.Ranges)+len(c.Ranges)) + +	i, j := 0, 0 +	for { +		var cur Range +		if i < len(s.Ranges) && j < len(c.Ranges) { +			if s.Ranges[i].Start < c.Ranges[j].Start { +				cur = s.Ranges[i] +				i++ +			} else { +				cur = c.Ranges[j] +				j++ +			} +		} else if i < len(s.Ranges) { +			cur = s.Ranges[i] +			i++ +		} else if j < len(c.Ranges) { +			cur = c.Ranges[j] +			j++ +		} else { +			break +		} + +		if n := len(out); n > 0 && cur.Start <= out[n-1].End { +			out[n-1].End = cur.End +		} else { +			out = append(out, cur) +		} +	} + +	s.Ranges = out +} + +// AppendRange adds r to s, if r is non-empty. +// If possible, it extends the last Range in s.Ranges; if not, it creates a new one. +func (s *Scope) AppendRange(r Range) { +	if r.End <= r.Start { +		return +	} +	i := len(s.Ranges) +	if i > 0 && s.Ranges[i-1].End == r.Start { +		s.Ranges[i-1].End = r.End +		return +	} +	s.Ranges = append(s.Ranges, r) +} + +type InlCalls struct { +	Calls []InlCall +} + +type InlCall struct { +	// index into ctx.InlTree describing the call inlined here +	InlIndex int + +	// Symbol of file containing inlined call site (really *obj.LSym). +	CallFile Sym + +	// Line number of inlined call site. +	CallLine uint32 + +	// Dwarf abstract subroutine symbol (really *obj.LSym). +	AbsFunSym Sym + +	// Indices of child inlines within Calls array above. +	Children []int + +	// entries in this list are PAUTO's created by the inliner to +	// capture the promoted formals and locals of the inlined callee. +	InlVars []*Var + +	// PC ranges for this inlined call. +	Ranges []Range + +	// Root call (not a child of some other call). +	Root bool +} + +// A Context specifies how to add data to a Sym. +type Context interface { +	PtrSize() int +	AddInt(s Sym, size int, i int64) +	AddBytes(s Sym, b []byte) +	AddAddress(s Sym, t interface{}, ofs int64) +	AddCURelativeAddress(s Sym, t interface{}, ofs int64) +	AddSectionOffset(s Sym, size int, t interface{}, ofs int64) +	AddDWARFAddrSectionOffset(s Sym, t interface{}, ofs int64) +	CurrentOffset(s Sym) int64 +	RecordDclReference(from Sym, to Sym, dclIdx int, inlIndex int) +	RecordChildDieOffsets(s Sym, vars []*Var, offsets []int32) +	AddString(s Sym, v string) +	AddFileRef(s Sym, f interface{}) +	Logf(format string, args ...interface{}) +} + +// AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding. +func AppendUleb128(b []byte, v uint64) []byte { +	for { +		c := uint8(v & 0x7f) +		v >>= 7 +		if v != 0 { +			c |= 0x80 +		} +		b = append(b, c) +		if c&0x80 == 0 { +			break +		} +	} +	return b +} + +// AppendSleb128 appends v to b using DWARF's signed LEB128 encoding. +func AppendSleb128(b []byte, v int64) []byte { +	for { +		c := uint8(v & 0x7f) +		s := uint8(v & 0x40) +		v >>= 7 +		if (v != -1 || s == 0) && (v != 0 || s != 0) { +			c |= 0x80 +		} +		b = append(b, c) +		if c&0x80 == 0 { +			break +		} +	} +	return b +} + +// sevenbits contains all unsigned seven bit numbers, indexed by their value. +var sevenbits = [...]byte{ +	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, +	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, +	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, +	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, +	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, +	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, +} + +// sevenBitU returns the unsigned LEB128 encoding of v if v is seven bits and nil otherwise. +// The contents of the returned slice must not be modified. +func sevenBitU(v int64) []byte { +	if uint64(v) < uint64(len(sevenbits)) { +		return sevenbits[v : v+1] +	} +	return nil +} + +// sevenBitS returns the signed LEB128 encoding of v if v is seven bits and nil otherwise. +// The contents of the returned slice must not be modified. +func sevenBitS(v int64) []byte { +	if uint64(v) <= 63 { +		return sevenbits[v : v+1] +	} +	if uint64(-v) <= 64 { +		return sevenbits[128+v : 128+v+1] +	} +	return nil +} + +// Uleb128put appends v to s using DWARF's unsigned LEB128 encoding. +func Uleb128put(ctxt Context, s Sym, v int64) { +	b := sevenBitU(v) +	if b == nil { +		var encbuf [20]byte +		b = AppendUleb128(encbuf[:0], uint64(v)) +	} +	ctxt.AddBytes(s, b) +} + +// Sleb128put appends v to s using DWARF's signed LEB128 encoding. +func Sleb128put(ctxt Context, s Sym, v int64) { +	b := sevenBitS(v) +	if b == nil { +		var encbuf [20]byte +		b = AppendSleb128(encbuf[:0], v) +	} +	ctxt.AddBytes(s, b) +} + +/* + * Defining Abbrevs. This is hardcoded on a per-platform basis (that is, + * each platform will see a fixed abbrev table for all objects); the number + * of abbrev entries is fairly small (compared to C++ objects).  The DWARF + * spec places no restriction on the ordering of attributes in the + * Abbrevs and DIEs, and we will always write them out in the order + * of declaration in the abbrev. + */ +type dwAttrForm struct { +	attr uint16 +	form uint8 +} + +// Go-specific type attributes. +const ( +	DW_AT_go_kind = 0x2900 +	DW_AT_go_key  = 0x2901 +	DW_AT_go_elem = 0x2902 +	// Attribute for DW_TAG_member of a struct type. +	// Nonzero value indicates the struct field is an embedded field. +	DW_AT_go_embedded_field = 0x2903 +	DW_AT_go_runtime_type   = 0x2904 + +	DW_AT_go_package_name = 0x2905 // Attribute for DW_TAG_compile_unit + +	DW_AT_internal_location = 253 // params and locals; not emitted +) + +// Index into the abbrevs table below. +// Keep in sync with ispubname() and ispubtype() in ld/dwarf.go. +// ispubtype considers >= NULLTYPE public +const ( +	DW_ABRV_NULL = iota +	DW_ABRV_COMPUNIT +	DW_ABRV_COMPUNIT_TEXTLESS +	DW_ABRV_FUNCTION +	DW_ABRV_FUNCTION_ABSTRACT +	DW_ABRV_FUNCTION_CONCRETE +	DW_ABRV_INLINED_SUBROUTINE +	DW_ABRV_INLINED_SUBROUTINE_RANGES +	DW_ABRV_VARIABLE +	DW_ABRV_INT_CONSTANT +	DW_ABRV_AUTO +	DW_ABRV_AUTO_LOCLIST +	DW_ABRV_AUTO_ABSTRACT +	DW_ABRV_AUTO_CONCRETE +	DW_ABRV_AUTO_CONCRETE_LOCLIST +	DW_ABRV_PARAM +	DW_ABRV_PARAM_LOCLIST +	DW_ABRV_PARAM_ABSTRACT +	DW_ABRV_PARAM_CONCRETE +	DW_ABRV_PARAM_CONCRETE_LOCLIST +	DW_ABRV_LEXICAL_BLOCK_RANGES +	DW_ABRV_LEXICAL_BLOCK_SIMPLE +	DW_ABRV_STRUCTFIELD +	DW_ABRV_FUNCTYPEPARAM +	DW_ABRV_DOTDOTDOT +	DW_ABRV_ARRAYRANGE +	DW_ABRV_NULLTYPE +	DW_ABRV_BASETYPE +	DW_ABRV_ARRAYTYPE +	DW_ABRV_CHANTYPE +	DW_ABRV_FUNCTYPE +	DW_ABRV_IFACETYPE +	DW_ABRV_MAPTYPE +	DW_ABRV_PTRTYPE +	DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6. +	DW_ABRV_SLICETYPE +	DW_ABRV_STRINGTYPE +	DW_ABRV_STRUCTTYPE +	DW_ABRV_TYPEDECL +	DW_NABRV +) + +type dwAbbrev struct { +	tag      uint8 +	children uint8 +	attr     []dwAttrForm +} + +var abbrevsFinalized bool + +// expandPseudoForm takes an input DW_FORM_xxx value and translates it +// into a platform-appropriate concrete form. Existing concrete/real +// DW_FORM values are left untouched. For the moment the only +// pseudo-form is DW_FORM_udata_pseudo, which gets expanded to +// DW_FORM_data4 on Darwin and DW_FORM_udata everywhere else. See +// issue #31459 for more context. +func expandPseudoForm(form uint8) uint8 { +	// Is this a pseudo-form? +	if form != DW_FORM_udata_pseudo { +		return form +	} +	expandedForm := DW_FORM_udata +	if objabi.GOOS == "darwin" { +		expandedForm = DW_FORM_data4 +	} +	return uint8(expandedForm) +} + +// Abbrevs() returns the finalized abbrev array for the platform, +// expanding any DW_FORM pseudo-ops to real values. +func Abbrevs() []dwAbbrev { +	if abbrevsFinalized { +		return abbrevs[:] +	} +	for i := 1; i < DW_NABRV; i++ { +		for j := 0; j < len(abbrevs[i].attr); j++ { +			abbrevs[i].attr[j].form = expandPseudoForm(abbrevs[i].attr[j].form) +		} +	} +	abbrevsFinalized = true +	return abbrevs[:] +} + +// abbrevs is a raw table of abbrev entries; it needs to be post-processed +// by the Abbrevs() function above prior to being consumed, to expand +// the 'pseudo-form' entries below to real DWARF form values. + +var abbrevs = [DW_NABRV]dwAbbrev{ +	/* The mandatory DW_ABRV_NULL entry. */ +	{0, 0, []dwAttrForm{}}, + +	/* COMPUNIT */ +	{ +		DW_TAG_compile_unit, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_language, DW_FORM_data1}, +			{DW_AT_stmt_list, DW_FORM_sec_offset}, +			{DW_AT_low_pc, DW_FORM_addr}, +			{DW_AT_ranges, DW_FORM_sec_offset}, +			{DW_AT_comp_dir, DW_FORM_string}, +			{DW_AT_producer, DW_FORM_string}, +			{DW_AT_go_package_name, DW_FORM_string}, +		}, +	}, + +	/* COMPUNIT_TEXTLESS */ +	{ +		DW_TAG_compile_unit, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_language, DW_FORM_data1}, +			{DW_AT_comp_dir, DW_FORM_string}, +			{DW_AT_producer, DW_FORM_string}, +			{DW_AT_go_package_name, DW_FORM_string}, +		}, +	}, + +	/* FUNCTION */ +	{ +		DW_TAG_subprogram, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_low_pc, DW_FORM_addr}, +			{DW_AT_high_pc, DW_FORM_addr}, +			{DW_AT_frame_base, DW_FORM_block1}, +			{DW_AT_decl_file, DW_FORM_data4}, +			{DW_AT_external, DW_FORM_flag}, +		}, +	}, + +	/* FUNCTION_ABSTRACT */ +	{ +		DW_TAG_subprogram, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_inline, DW_FORM_data1}, +			{DW_AT_external, DW_FORM_flag}, +		}, +	}, + +	/* FUNCTION_CONCRETE */ +	{ +		DW_TAG_subprogram, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_low_pc, DW_FORM_addr}, +			{DW_AT_high_pc, DW_FORM_addr}, +			{DW_AT_frame_base, DW_FORM_block1}, +		}, +	}, + +	/* INLINED_SUBROUTINE */ +	{ +		DW_TAG_inlined_subroutine, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_low_pc, DW_FORM_addr}, +			{DW_AT_high_pc, DW_FORM_addr}, +			{DW_AT_call_file, DW_FORM_data4}, +			{DW_AT_call_line, DW_FORM_udata_pseudo}, // pseudo-form +		}, +	}, + +	/* INLINED_SUBROUTINE_RANGES */ +	{ +		DW_TAG_inlined_subroutine, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_ranges, DW_FORM_sec_offset}, +			{DW_AT_call_file, DW_FORM_data4}, +			{DW_AT_call_line, DW_FORM_udata_pseudo}, // pseudo-form +		}, +	}, + +	/* VARIABLE */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_location, DW_FORM_block1}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_external, DW_FORM_flag}, +		}, +	}, + +	/* INT CONSTANT */ +	{ +		DW_TAG_constant, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_const_value, DW_FORM_sdata}, +		}, +	}, + +	/* AUTO */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_decl_line, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_block1}, +		}, +	}, + +	/* AUTO_LOCLIST */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_decl_line, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_sec_offset}, +		}, +	}, + +	/* AUTO_ABSTRACT */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_decl_line, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +		}, +	}, + +	/* AUTO_CONCRETE */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_block1}, +		}, +	}, + +	/* AUTO_CONCRETE_LOCLIST */ +	{ +		DW_TAG_variable, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_sec_offset}, +		}, +	}, + +	/* PARAM */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_variable_parameter, DW_FORM_flag}, +			{DW_AT_decl_line, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_block1}, +		}, +	}, + +	/* PARAM_LOCLIST */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_variable_parameter, DW_FORM_flag}, +			{DW_AT_decl_line, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_sec_offset}, +		}, +	}, + +	/* PARAM_ABSTRACT */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_variable_parameter, DW_FORM_flag}, +			{DW_AT_type, DW_FORM_ref_addr}, +		}, +	}, + +	/* PARAM_CONCRETE */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_block1}, +		}, +	}, + +	/* PARAM_CONCRETE_LOCLIST */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_abstract_origin, DW_FORM_ref_addr}, +			{DW_AT_location, DW_FORM_sec_offset}, +		}, +	}, + +	/* LEXICAL_BLOCK_RANGES */ +	{ +		DW_TAG_lexical_block, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_ranges, DW_FORM_sec_offset}, +		}, +	}, + +	/* LEXICAL_BLOCK_SIMPLE */ +	{ +		DW_TAG_lexical_block, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_low_pc, DW_FORM_addr}, +			{DW_AT_high_pc, DW_FORM_addr}, +		}, +	}, + +	/* STRUCTFIELD */ +	{ +		DW_TAG_member, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_data_member_location, DW_FORM_udata}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_go_embedded_field, DW_FORM_flag}, +		}, +	}, + +	/* FUNCTYPEPARAM */ +	{ +		DW_TAG_formal_parameter, +		DW_CHILDREN_no, + +		// No name! +		[]dwAttrForm{ +			{DW_AT_type, DW_FORM_ref_addr}, +		}, +	}, + +	/* DOTDOTDOT */ +	{ +		DW_TAG_unspecified_parameters, +		DW_CHILDREN_no, +		[]dwAttrForm{}, +	}, + +	/* ARRAYRANGE */ +	{ +		DW_TAG_subrange_type, +		DW_CHILDREN_no, + +		// No name! +		[]dwAttrForm{ +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_count, DW_FORM_udata}, +		}, +	}, + +	// Below here are the types considered public by ispubtype +	/* NULLTYPE */ +	{ +		DW_TAG_unspecified_type, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +		}, +	}, + +	/* BASETYPE */ +	{ +		DW_TAG_base_type, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_encoding, DW_FORM_data1}, +			{DW_AT_byte_size, DW_FORM_data1}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* ARRAYTYPE */ +	// child is subrange with upper bound +	{ +		DW_TAG_array_type, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_byte_size, DW_FORM_udata}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* CHANTYPE */ +	{ +		DW_TAG_typedef, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +			{DW_AT_go_elem, DW_FORM_ref_addr}, +		}, +	}, + +	/* FUNCTYPE */ +	{ +		DW_TAG_subroutine_type, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_byte_size, DW_FORM_udata}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* IFACETYPE */ +	{ +		DW_TAG_typedef, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* MAPTYPE */ +	{ +		DW_TAG_typedef, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +			{DW_AT_go_key, DW_FORM_ref_addr}, +			{DW_AT_go_elem, DW_FORM_ref_addr}, +		}, +	}, + +	/* PTRTYPE */ +	{ +		DW_TAG_pointer_type, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* BARE_PTRTYPE */ +	{ +		DW_TAG_pointer_type, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +		}, +	}, + +	/* SLICETYPE */ +	{ +		DW_TAG_structure_type, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_byte_size, DW_FORM_udata}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +			{DW_AT_go_elem, DW_FORM_ref_addr}, +		}, +	}, + +	/* STRINGTYPE */ +	{ +		DW_TAG_structure_type, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_byte_size, DW_FORM_udata}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* STRUCTTYPE */ +	{ +		DW_TAG_structure_type, +		DW_CHILDREN_yes, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_byte_size, DW_FORM_udata}, +			{DW_AT_go_kind, DW_FORM_data1}, +			{DW_AT_go_runtime_type, DW_FORM_addr}, +		}, +	}, + +	/* TYPEDECL */ +	{ +		DW_TAG_typedef, +		DW_CHILDREN_no, +		[]dwAttrForm{ +			{DW_AT_name, DW_FORM_string}, +			{DW_AT_type, DW_FORM_ref_addr}, +		}, +	}, +} + +// GetAbbrev returns the contents of the .debug_abbrev section. +func GetAbbrev() []byte { +	abbrevs := Abbrevs() +	var buf []byte +	for i := 1; i < DW_NABRV; i++ { +		// See section 7.5.3 +		buf = AppendUleb128(buf, uint64(i)) +		buf = AppendUleb128(buf, uint64(abbrevs[i].tag)) +		buf = append(buf, abbrevs[i].children) +		for _, f := range abbrevs[i].attr { +			buf = AppendUleb128(buf, uint64(f.attr)) +			buf = AppendUleb128(buf, uint64(f.form)) +		} +		buf = append(buf, 0, 0) +	} +	return append(buf, 0) +} + +/* + * Debugging Information Entries and their attributes. + */ + +// DWAttr represents an attribute of a DWDie. +// +// For DW_CLS_string and _block, value should contain the length, and +// data the data, for _reference, value is 0 and data is a DWDie* to +// the referenced instance, for all others, value is the whole thing +// and data is null. +type DWAttr struct { +	Link  *DWAttr +	Atr   uint16 // DW_AT_ +	Cls   uint8  // DW_CLS_ +	Value int64 +	Data  interface{} +} + +// DWDie represents a DWARF debug info entry. +type DWDie struct { +	Abbrev int +	Link   *DWDie +	Child  *DWDie +	Attr   *DWAttr +	Sym    Sym +} + +func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error { +	switch form { +	case DW_FORM_addr: // address +		// Allow nil addresses for DW_AT_go_runtime_type. +		if data == nil && value == 0 { +			ctxt.AddInt(s, ctxt.PtrSize(), 0) +			break +		} +		if cls == DW_CLS_GO_TYPEREF { +			ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, value) +			break +		} +		ctxt.AddAddress(s, data, value) + +	case DW_FORM_block1: // block +		if cls == DW_CLS_ADDRESS { +			ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize())) +			ctxt.AddInt(s, 1, DW_OP_addr) +			ctxt.AddAddress(s, data, 0) +			break +		} + +		value &= 0xff +		ctxt.AddInt(s, 1, value) +		p := data.([]byte)[:value] +		ctxt.AddBytes(s, p) + +	case DW_FORM_block2: // block +		value &= 0xffff + +		ctxt.AddInt(s, 2, value) +		p := data.([]byte)[:value] +		ctxt.AddBytes(s, p) + +	case DW_FORM_block4: // block +		value &= 0xffffffff + +		ctxt.AddInt(s, 4, value) +		p := data.([]byte)[:value] +		ctxt.AddBytes(s, p) + +	case DW_FORM_block: // block +		Uleb128put(ctxt, s, value) + +		p := data.([]byte)[:value] +		ctxt.AddBytes(s, p) + +	case DW_FORM_data1: // constant +		ctxt.AddInt(s, 1, value) + +	case DW_FORM_data2: // constant +		ctxt.AddInt(s, 2, value) + +	case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr +		if cls == DW_CLS_PTR { // DW_AT_stmt_list and DW_AT_ranges +			ctxt.AddDWARFAddrSectionOffset(s, data, value) +			break +		} +		ctxt.AddInt(s, 4, value) + +	case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr +		ctxt.AddInt(s, 8, value) + +	case DW_FORM_sdata: // constant +		Sleb128put(ctxt, s, value) + +	case DW_FORM_udata: // constant +		Uleb128put(ctxt, s, value) + +	case DW_FORM_string: // string +		str := data.(string) +		ctxt.AddString(s, str) +		// TODO(ribrdb): verify padded strings are never used and remove this +		for i := int64(len(str)); i < value; i++ { +			ctxt.AddInt(s, 1, 0) +		} + +	case DW_FORM_flag: // flag +		if value != 0 { +			ctxt.AddInt(s, 1, 1) +		} else { +			ctxt.AddInt(s, 1, 0) +		} + +	// As of DWARF 3 the ref_addr is always 32 bits, unless emitting a large +	// (> 4 GB of debug info aka "64-bit") unit, which we don't implement. +	case DW_FORM_ref_addr: // reference to a DIE in the .info section +		fallthrough +	case DW_FORM_sec_offset: // offset into a DWARF section other than .info +		if data == nil { +			return fmt.Errorf("dwarf: null reference in %d", abbrev) +		} +		ctxt.AddDWARFAddrSectionOffset(s, data, value) + +	case DW_FORM_ref1, // reference within the compilation unit +		DW_FORM_ref2,      // reference +		DW_FORM_ref4,      // reference +		DW_FORM_ref8,      // reference +		DW_FORM_ref_udata, // reference + +		DW_FORM_strp,     // string +		DW_FORM_indirect: // (see Section 7.5.3) +		fallthrough +	default: +		return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls) +	} +	return nil +} + +// PutAttrs writes the attributes for a DIE to symbol 's'. +// +// Note that we can (and do) add arbitrary attributes to a DIE, but +// only the ones actually listed in the Abbrev will be written out. +func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) { +	abbrevs := Abbrevs() +Outer: +	for _, f := range abbrevs[abbrev].attr { +		for ap := attr; ap != nil; ap = ap.Link { +			if ap.Atr == f.attr { +				putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data) +				continue Outer +			} +		} + +		putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil) +	} +} + +// HasChildren reports whether 'die' uses an abbrev that supports children. +func HasChildren(die *DWDie) bool { +	abbrevs := Abbrevs() +	return abbrevs[die.Abbrev].children != 0 +} + +// PutIntConst writes a DIE for an integer constant +func PutIntConst(ctxt Context, info, typ Sym, name string, val int64) { +	Uleb128put(ctxt, info, DW_ABRV_INT_CONSTANT) +	putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name) +	putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, typ) +	putattr(ctxt, info, DW_ABRV_INT_CONSTANT, DW_FORM_sdata, DW_CLS_CONSTANT, val, nil) +} + +// PutBasedRanges writes a range table to sym. All addresses in ranges are +// relative to some base address, which must be arranged by the caller +// (e.g., with a DW_AT_low_pc attribute, or in a BASE-prefixed range). +func PutBasedRanges(ctxt Context, sym Sym, ranges []Range) { +	ps := ctxt.PtrSize() +	// Write ranges. +	for _, r := range ranges { +		ctxt.AddInt(sym, ps, r.Start) +		ctxt.AddInt(sym, ps, r.End) +	} +	// Write trailer. +	ctxt.AddInt(sym, ps, 0) +	ctxt.AddInt(sym, ps, 0) +} + +// PutRanges writes a range table to s.Ranges. +// All addresses in ranges are relative to s.base. +func (s *FnState) PutRanges(ctxt Context, ranges []Range) { +	ps := ctxt.PtrSize() +	sym, base := s.Ranges, s.StartPC + +	if s.UseBASEntries { +		// Using a Base Address Selection Entry reduces the number of relocations, but +		// this is not done on macOS because it is not supported by dsymutil/dwarfdump/lldb +		ctxt.AddInt(sym, ps, -1) +		ctxt.AddAddress(sym, base, 0) +		PutBasedRanges(ctxt, sym, ranges) +		return +	} + +	// Write ranges full of relocations +	for _, r := range ranges { +		ctxt.AddCURelativeAddress(sym, base, r.Start) +		ctxt.AddCURelativeAddress(sym, base, r.End) +	} +	// Write trailer. +	ctxt.AddInt(sym, ps, 0) +	ctxt.AddInt(sym, ps, 0) +} + +// Return TRUE if the inlined call in the specified slot is empty, +// meaning it has a zero-length range (no instructions), and all +// of its children are empty. +func isEmptyInlinedCall(slot int, calls *InlCalls) bool { +	ic := &calls.Calls[slot] +	if ic.InlIndex == -2 { +		return true +	} +	live := false +	for _, k := range ic.Children { +		if !isEmptyInlinedCall(k, calls) { +			live = true +		} +	} +	if len(ic.Ranges) > 0 { +		live = true +	} +	if !live { +		ic.InlIndex = -2 +	} +	return !live +} + +// Slot -1:    return top-level inlines +// Slot >= 0:  return children of that slot +func inlChildren(slot int, calls *InlCalls) []int { +	var kids []int +	if slot != -1 { +		for _, k := range calls.Calls[slot].Children { +			if !isEmptyInlinedCall(k, calls) { +				kids = append(kids, k) +			} +		} +	} else { +		for k := 0; k < len(calls.Calls); k += 1 { +			if calls.Calls[k].Root && !isEmptyInlinedCall(k, calls) { +				kids = append(kids, k) +			} +		} +	} +	return kids +} + +func inlinedVarTable(inlcalls *InlCalls) map[*Var]bool { +	vars := make(map[*Var]bool) +	for _, ic := range inlcalls.Calls { +		for _, v := range ic.InlVars { +			vars[v] = true +		} +	} +	return vars +} + +// The s.Scopes slice contains variables were originally part of the +// function being emitted, as well as variables that were imported +// from various callee functions during the inlining process. This +// function prunes out any variables from the latter category (since +// they will be emitted as part of DWARF inlined_subroutine DIEs) and +// then generates scopes for vars in the former category. +func putPrunedScopes(ctxt Context, s *FnState, fnabbrev int) error { +	if len(s.Scopes) == 0 { +		return nil +	} +	scopes := make([]Scope, len(s.Scopes), len(s.Scopes)) +	pvars := inlinedVarTable(&s.InlCalls) +	for k, s := range s.Scopes { +		var pruned Scope = Scope{Parent: s.Parent, Ranges: s.Ranges} +		for i := 0; i < len(s.Vars); i++ { +			_, found := pvars[s.Vars[i]] +			if !found { +				pruned.Vars = append(pruned.Vars, s.Vars[i]) +			} +		} +		sort.Sort(byChildIndex(pruned.Vars)) +		scopes[k] = pruned +	} +	var encbuf [20]byte +	if putscope(ctxt, s, scopes, 0, fnabbrev, encbuf[:0]) < int32(len(scopes)) { +		return errors.New("multiple toplevel scopes") +	} +	return nil +} + +// Emit DWARF attributes and child DIEs for an 'abstract' subprogram. +// The abstract subprogram DIE for a function contains its +// location-independent attributes (name, type, etc). Other instances +// of the function (any inlined copy of it, or the single out-of-line +// 'concrete' instance) will contain a pointer back to this abstract +// DIE (as a space-saving measure, so that name/type etc doesn't have +// to be repeated for each inlined copy). +func PutAbstractFunc(ctxt Context, s *FnState) error { + +	if logDwarf { +		ctxt.Logf("PutAbstractFunc(%v)\n", s.Absfn) +	} + +	abbrev := DW_ABRV_FUNCTION_ABSTRACT +	Uleb128put(ctxt, s.Absfn, int64(abbrev)) + +	fullname := s.Name +	if strings.HasPrefix(s.Name, "\"\".") { +		// Generate a fully qualified name for the function in the +		// abstract case. This is so as to avoid the need for the +		// linker to process the DIE with patchDWARFName(); we can't +		// allow the name attribute of an abstract subprogram DIE to +		// be rewritten, since it would change the offsets of the +		// child DIEs (which we're relying on in order for abstract +		// origin references to work). +		fullname = objabi.PathToPrefix(s.Importpath) + "." + s.Name[3:] +	} +	putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname) + +	// DW_AT_inlined value +	putattr(ctxt, s.Absfn, abbrev, DW_FORM_data1, DW_CLS_CONSTANT, int64(DW_INL_inlined), nil) + +	var ev int64 +	if s.External { +		ev = 1 +	} +	putattr(ctxt, s.Absfn, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0) + +	// Child variables (may be empty) +	var flattened []*Var + +	// This slice will hold the offset in bytes for each child var DIE +	// with respect to the start of the parent subprogram DIE. +	var offsets []int32 + +	// Scopes/vars +	if len(s.Scopes) > 0 { +		// For abstract subprogram DIEs we want to flatten out scope info: +		// lexical scope DIEs contain range and/or hi/lo PC attributes, +		// which we explicitly don't want for the abstract subprogram DIE. +		pvars := inlinedVarTable(&s.InlCalls) +		for _, scope := range s.Scopes { +			for i := 0; i < len(scope.Vars); i++ { +				_, found := pvars[scope.Vars[i]] +				if found || !scope.Vars[i].IsInAbstract { +					continue +				} +				flattened = append(flattened, scope.Vars[i]) +			} +		} +		if len(flattened) > 0 { +			sort.Sort(byChildIndex(flattened)) + +			if logDwarf { +				ctxt.Logf("putAbstractScope(%v): vars:", s.Info) +				for i, v := range flattened { +					ctxt.Logf(" %d:%s", i, v.Name) +				} +				ctxt.Logf("\n") +			} + +			// This slice will hold the offset in bytes for each child +			// variable DIE with respect to the start of the parent +			// subprogram DIE. +			for _, v := range flattened { +				offsets = append(offsets, int32(ctxt.CurrentOffset(s.Absfn))) +				putAbstractVar(ctxt, s.Absfn, v) +			} +		} +	} +	ctxt.RecordChildDieOffsets(s.Absfn, flattened, offsets) + +	Uleb128put(ctxt, s.Absfn, 0) +	return nil +} + +// Emit DWARF attributes and child DIEs for an inlined subroutine. The +// first attribute of an inlined subroutine DIE is a reference back to +// its corresponding 'abstract' DIE (containing location-independent +// attributes such as name, type, etc). Inlined subroutine DIEs can +// have other inlined subroutine DIEs as children. +func PutInlinedFunc(ctxt Context, s *FnState, callersym Sym, callIdx int) error { +	ic := s.InlCalls.Calls[callIdx] +	callee := ic.AbsFunSym + +	abbrev := DW_ABRV_INLINED_SUBROUTINE_RANGES +	if len(ic.Ranges) == 1 { +		abbrev = DW_ABRV_INLINED_SUBROUTINE +	} +	Uleb128put(ctxt, s.Info, int64(abbrev)) + +	if logDwarf { +		ctxt.Logf("PutInlinedFunc(caller=%v,callee=%v,abbrev=%d)\n", callersym, callee, abbrev) +	} + +	// Abstract origin. +	putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, callee) + +	if abbrev == DW_ABRV_INLINED_SUBROUTINE_RANGES { +		putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges) +		s.PutRanges(ctxt, ic.Ranges) +	} else { +		st := ic.Ranges[0].Start +		en := ic.Ranges[0].End +		putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, st, s.StartPC) +		putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, en, s.StartPC) +	} + +	// Emit call file, line attrs. +	ctxt.AddFileRef(s.Info, ic.CallFile) +	form := int(expandPseudoForm(DW_FORM_udata_pseudo)) +	putattr(ctxt, s.Info, abbrev, form, DW_CLS_CONSTANT, int64(ic.CallLine), nil) + +	// Variables associated with this inlined routine instance. +	vars := ic.InlVars +	sort.Sort(byChildIndex(vars)) +	inlIndex := ic.InlIndex +	var encbuf [20]byte +	for _, v := range vars { +		if !v.IsInAbstract { +			continue +		} +		putvar(ctxt, s, v, callee, abbrev, inlIndex, encbuf[:0]) +	} + +	// Children of this inline. +	for _, sib := range inlChildren(callIdx, &s.InlCalls) { +		absfn := s.InlCalls.Calls[sib].AbsFunSym +		err := PutInlinedFunc(ctxt, s, absfn, sib) +		if err != nil { +			return err +		} +	} + +	Uleb128put(ctxt, s.Info, 0) +	return nil +} + +// Emit DWARF attributes and child DIEs for a 'concrete' subprogram, +// meaning the out-of-line copy of a function that was inlined at some +// point during the compilation of its containing package. The first +// attribute for a concrete DIE is a reference to the 'abstract' DIE +// for the function (which holds location-independent attributes such +// as name, type), then the remainder of the attributes are specific +// to this instance (location, frame base, etc). +func PutConcreteFunc(ctxt Context, s *FnState) error { +	if logDwarf { +		ctxt.Logf("PutConcreteFunc(%v)\n", s.Info) +	} +	abbrev := DW_ABRV_FUNCTION_CONCRETE +	Uleb128put(ctxt, s.Info, int64(abbrev)) + +	// Abstract origin. +	putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, s.Absfn) + +	// Start/end PC. +	putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC) +	putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC) + +	// cfa / frame base +	putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa}) + +	// Scopes +	if err := putPrunedScopes(ctxt, s, abbrev); err != nil { +		return err +	} + +	// Inlined subroutines. +	for _, sib := range inlChildren(-1, &s.InlCalls) { +		absfn := s.InlCalls.Calls[sib].AbsFunSym +		err := PutInlinedFunc(ctxt, s, absfn, sib) +		if err != nil { +			return err +		} +	} + +	Uleb128put(ctxt, s.Info, 0) +	return nil +} + +// Emit DWARF attributes and child DIEs for a subprogram. Here +// 'default' implies that the function in question was not inlined +// when its containing package was compiled (hence there is no need to +// emit an abstract version for it to use as a base for inlined +// routine records). +func PutDefaultFunc(ctxt Context, s *FnState) error { +	if logDwarf { +		ctxt.Logf("PutDefaultFunc(%v)\n", s.Info) +	} +	abbrev := DW_ABRV_FUNCTION +	Uleb128put(ctxt, s.Info, int64(abbrev)) + +	// Expand '"".' to import path. +	name := s.Name +	if s.Importpath != "" { +		name = strings.Replace(name, "\"\".", objabi.PathToPrefix(s.Importpath)+".", -1) +	} + +	putattr(ctxt, s.Info, DW_ABRV_FUNCTION, DW_FORM_string, DW_CLS_STRING, int64(len(name)), name) +	putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, 0, s.StartPC) +	putattr(ctxt, s.Info, abbrev, DW_FORM_addr, DW_CLS_ADDRESS, s.Size, s.StartPC) +	putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, 1, []byte{DW_OP_call_frame_cfa}) +	ctxt.AddFileRef(s.Info, s.Filesym) + +	var ev int64 +	if s.External { +		ev = 1 +	} +	putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, ev, 0) + +	// Scopes +	if err := putPrunedScopes(ctxt, s, abbrev); err != nil { +		return err +	} + +	// Inlined subroutines. +	for _, sib := range inlChildren(-1, &s.InlCalls) { +		absfn := s.InlCalls.Calls[sib].AbsFunSym +		err := PutInlinedFunc(ctxt, s, absfn, sib) +		if err != nil { +			return err +		} +	} + +	Uleb128put(ctxt, s.Info, 0) +	return nil +} + +func putscope(ctxt Context, s *FnState, scopes []Scope, curscope int32, fnabbrev int, encbuf []byte) int32 { + +	if logDwarf { +		ctxt.Logf("putscope(%v,%d): vars:", s.Info, curscope) +		for i, v := range scopes[curscope].Vars { +			ctxt.Logf(" %d:%d:%s", i, v.ChildIndex, v.Name) +		} +		ctxt.Logf("\n") +	} + +	for _, v := range scopes[curscope].Vars { +		putvar(ctxt, s, v, s.Absfn, fnabbrev, -1, encbuf) +	} +	this := curscope +	curscope++ +	for curscope < int32(len(scopes)) { +		scope := scopes[curscope] +		if scope.Parent != this { +			return curscope +		} + +		if len(scopes[curscope].Vars) == 0 { +			curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf) +			continue +		} + +		if len(scope.Ranges) == 1 { +			Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE) +			putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].Start, s.StartPC) +			putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_SIMPLE, DW_FORM_addr, DW_CLS_ADDRESS, scope.Ranges[0].End, s.StartPC) +		} else { +			Uleb128put(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES) +			putattr(ctxt, s.Info, DW_ABRV_LEXICAL_BLOCK_RANGES, DW_FORM_sec_offset, DW_CLS_PTR, s.Ranges.Length(ctxt), s.Ranges) + +			s.PutRanges(ctxt, scope.Ranges) +		} + +		curscope = putscope(ctxt, s, scopes, curscope, fnabbrev, encbuf) + +		Uleb128put(ctxt, s.Info, 0) +	} +	return curscope +} + +// Given a default var abbrev code, select corresponding concrete code. +func concreteVarAbbrev(varAbbrev int) int { +	switch varAbbrev { +	case DW_ABRV_AUTO: +		return DW_ABRV_AUTO_CONCRETE +	case DW_ABRV_PARAM: +		return DW_ABRV_PARAM_CONCRETE +	case DW_ABRV_AUTO_LOCLIST: +		return DW_ABRV_AUTO_CONCRETE_LOCLIST +	case DW_ABRV_PARAM_LOCLIST: +		return DW_ABRV_PARAM_CONCRETE_LOCLIST +	default: +		panic("should never happen") +	} +} + +// Pick the correct abbrev code for variable or parameter DIE. +func determineVarAbbrev(v *Var, fnabbrev int) (int, bool, bool) { +	abbrev := v.Abbrev + +	// If the variable was entirely optimized out, don't emit a location list; +	// convert to an inline abbreviation and emit an empty location. +	missing := false +	switch { +	case abbrev == DW_ABRV_AUTO_LOCLIST && v.PutLocationList == nil: +		missing = true +		abbrev = DW_ABRV_AUTO +	case abbrev == DW_ABRV_PARAM_LOCLIST && v.PutLocationList == nil: +		missing = true +		abbrev = DW_ABRV_PARAM +	} + +	// Determine whether to use a concrete variable or regular variable DIE. +	concrete := true +	switch fnabbrev { +	case DW_ABRV_FUNCTION: +		concrete = false +		break +	case DW_ABRV_FUNCTION_CONCRETE: +		// If we're emitting a concrete subprogram DIE and the variable +		// in question is not part of the corresponding abstract function DIE, +		// then use the default (non-concrete) abbrev for this param. +		if !v.IsInAbstract { +			concrete = false +		} +	case DW_ABRV_INLINED_SUBROUTINE, DW_ABRV_INLINED_SUBROUTINE_RANGES: +	default: +		panic("should never happen") +	} + +	// Select proper abbrev based on concrete/non-concrete +	if concrete { +		abbrev = concreteVarAbbrev(abbrev) +	} + +	return abbrev, missing, concrete +} + +func abbrevUsesLoclist(abbrev int) bool { +	switch abbrev { +	case DW_ABRV_AUTO_LOCLIST, DW_ABRV_AUTO_CONCRETE_LOCLIST, +		DW_ABRV_PARAM_LOCLIST, DW_ABRV_PARAM_CONCRETE_LOCLIST: +		return true +	default: +		return false +	} +} + +// Emit DWARF attributes for a variable belonging to an 'abstract' subprogram. +func putAbstractVar(ctxt Context, info Sym, v *Var) { +	// Remap abbrev +	abbrev := v.Abbrev +	switch abbrev { +	case DW_ABRV_AUTO, DW_ABRV_AUTO_LOCLIST: +		abbrev = DW_ABRV_AUTO_ABSTRACT +	case DW_ABRV_PARAM, DW_ABRV_PARAM_LOCLIST: +		abbrev = DW_ABRV_PARAM_ABSTRACT +	} + +	Uleb128put(ctxt, info, int64(abbrev)) +	putattr(ctxt, info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(v.Name)), v.Name) + +	// Isreturn attribute if this is a param +	if abbrev == DW_ABRV_PARAM_ABSTRACT { +		var isReturn int64 +		if v.IsReturnValue { +			isReturn = 1 +		} +		putattr(ctxt, info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil) +	} + +	// Line +	if abbrev != DW_ABRV_PARAM_ABSTRACT { +		// See issue 23374 for more on why decl line is skipped for abs params. +		putattr(ctxt, info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil) +	} + +	// Type +	putattr(ctxt, info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type) + +	// Var has no children => no terminator +} + +func putvar(ctxt Context, s *FnState, v *Var, absfn Sym, fnabbrev, inlIndex int, encbuf []byte) { +	// Remap abbrev according to parent DIE abbrev +	abbrev, missing, concrete := determineVarAbbrev(v, fnabbrev) + +	Uleb128put(ctxt, s.Info, int64(abbrev)) + +	// Abstract origin for concrete / inlined case +	if concrete { +		// Here we are making a reference to a child DIE of an abstract +		// function subprogram DIE. The child DIE has no LSym, so instead +		// after the call to 'putattr' below we make a call to register +		// the child DIE reference. +		putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, absfn) +		ctxt.RecordDclReference(s.Info, absfn, int(v.ChildIndex), inlIndex) +	} else { +		// Var name, line for abstract and default cases +		n := v.Name +		putattr(ctxt, s.Info, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(n)), n) +		if abbrev == DW_ABRV_PARAM || abbrev == DW_ABRV_PARAM_LOCLIST || abbrev == DW_ABRV_PARAM_ABSTRACT { +			var isReturn int64 +			if v.IsReturnValue { +				isReturn = 1 +			} +			putattr(ctxt, s.Info, abbrev, DW_FORM_flag, DW_CLS_FLAG, isReturn, nil) +		} +		putattr(ctxt, s.Info, abbrev, DW_FORM_udata, DW_CLS_CONSTANT, int64(v.DeclLine), nil) +		putattr(ctxt, s.Info, abbrev, DW_FORM_ref_addr, DW_CLS_REFERENCE, 0, v.Type) +	} + +	if abbrevUsesLoclist(abbrev) { +		putattr(ctxt, s.Info, abbrev, DW_FORM_sec_offset, DW_CLS_PTR, s.Loc.Length(ctxt), s.Loc) +		v.PutLocationList(s.Loc, s.StartPC) +	} else { +		loc := encbuf[:0] +		switch { +		case missing: +			break // no location +		case v.StackOffset == 0: +			loc = append(loc, DW_OP_call_frame_cfa) +		default: +			loc = append(loc, DW_OP_fbreg) +			loc = AppendSleb128(loc, int64(v.StackOffset)) +		} +		putattr(ctxt, s.Info, abbrev, DW_FORM_block1, DW_CLS_BLOCK, int64(len(loc)), loc) +	} + +	// Var has no children => no terminator +} + +// VarsByOffset attaches the methods of sort.Interface to []*Var, +// sorting in increasing StackOffset. +type VarsByOffset []*Var + +func (s VarsByOffset) Len() int           { return len(s) } +func (s VarsByOffset) Less(i, j int) bool { return s[i].StackOffset < s[j].StackOffset } +func (s VarsByOffset) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } + +// byChildIndex implements sort.Interface for []*dwarf.Var by child index. +type byChildIndex []*Var + +func (s byChildIndex) Len() int           { return len(s) } +func (s byChildIndex) Less(i, j int) bool { return s[i].ChildIndex < s[j].ChildIndex } +func (s byChildIndex) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } + +// IsDWARFEnabledOnAIX returns true if DWARF is possible on the +// current extld. +// AIX ld doesn't support DWARF with -bnoobjreorder with version +// prior to 7.2.2. +func IsDWARFEnabledOnAIXLd(extld string) (bool, error) { +	out, err := exec.Command(extld, "-Wl,-V").CombinedOutput() +	if err != nil { +		// The normal output should display ld version and +		// then fails because ".main" is not defined: +		// ld: 0711-317 ERROR: Undefined symbol: .main +		if !bytes.Contains(out, []byte("0711-317")) { +			return false, fmt.Errorf("%s -Wl,-V failed: %v\n%s", extld, err, out) +		} +	} +	// gcc -Wl,-V output should be: +	//   /usr/bin/ld: LD X.X.X(date) +	//   ... +	out = bytes.TrimPrefix(out, []byte("/usr/bin/ld: LD ")) +	vers := string(bytes.Split(out, []byte("("))[0]) +	subvers := strings.Split(vers, ".") +	if len(subvers) != 3 { +		return false, fmt.Errorf("cannot parse %s -Wl,-V (%s): %v\n", extld, out, err) +	} +	if v, err := strconv.Atoi(subvers[0]); err != nil || v < 7 { +		return false, nil +	} else if v > 7 { +		return true, nil +	} +	if v, err := strconv.Atoi(subvers[1]); err != nil || v < 2 { +		return false, nil +	} else if v > 2 { +		return true, nil +	} +	if v, err := strconv.Atoi(subvers[2]); err != nil || v < 2 { +		return false, nil +	} +	return true, nil +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go new file mode 100644 index 000000000..e2716e506 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/dwarf/dwarf_defs.go @@ -0,0 +1,493 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package dwarf + +// Cut, pasted, tr-and-awk'ed from tables in +// http://dwarfstd.org/doc/Dwarf3.pdf + +// Table 18 +const ( +	DW_TAG_array_type               = 0x01 +	DW_TAG_class_type               = 0x02 +	DW_TAG_entry_point              = 0x03 +	DW_TAG_enumeration_type         = 0x04 +	DW_TAG_formal_parameter         = 0x05 +	DW_TAG_imported_declaration     = 0x08 +	DW_TAG_label                    = 0x0a +	DW_TAG_lexical_block            = 0x0b +	DW_TAG_member                   = 0x0d +	DW_TAG_pointer_type             = 0x0f +	DW_TAG_reference_type           = 0x10 +	DW_TAG_compile_unit             = 0x11 +	DW_TAG_string_type              = 0x12 +	DW_TAG_structure_type           = 0x13 +	DW_TAG_subroutine_type          = 0x15 +	DW_TAG_typedef                  = 0x16 +	DW_TAG_union_type               = 0x17 +	DW_TAG_unspecified_parameters   = 0x18 +	DW_TAG_variant                  = 0x19 +	DW_TAG_common_block             = 0x1a +	DW_TAG_common_inclusion         = 0x1b +	DW_TAG_inheritance              = 0x1c +	DW_TAG_inlined_subroutine       = 0x1d +	DW_TAG_module                   = 0x1e +	DW_TAG_ptr_to_member_type       = 0x1f +	DW_TAG_set_type                 = 0x20 +	DW_TAG_subrange_type            = 0x21 +	DW_TAG_with_stmt                = 0x22 +	DW_TAG_access_declaration       = 0x23 +	DW_TAG_base_type                = 0x24 +	DW_TAG_catch_block              = 0x25 +	DW_TAG_const_type               = 0x26 +	DW_TAG_constant                 = 0x27 +	DW_TAG_enumerator               = 0x28 +	DW_TAG_file_type                = 0x29 +	DW_TAG_friend                   = 0x2a +	DW_TAG_namelist                 = 0x2b +	DW_TAG_namelist_item            = 0x2c +	DW_TAG_packed_type              = 0x2d +	DW_TAG_subprogram               = 0x2e +	DW_TAG_template_type_parameter  = 0x2f +	DW_TAG_template_value_parameter = 0x30 +	DW_TAG_thrown_type              = 0x31 +	DW_TAG_try_block                = 0x32 +	DW_TAG_variant_part             = 0x33 +	DW_TAG_variable                 = 0x34 +	DW_TAG_volatile_type            = 0x35 +	// Dwarf3 +	DW_TAG_dwarf_procedure  = 0x36 +	DW_TAG_restrict_type    = 0x37 +	DW_TAG_interface_type   = 0x38 +	DW_TAG_namespace        = 0x39 +	DW_TAG_imported_module  = 0x3a +	DW_TAG_unspecified_type = 0x3b +	DW_TAG_partial_unit     = 0x3c +	DW_TAG_imported_unit    = 0x3d +	DW_TAG_condition        = 0x3f +	DW_TAG_shared_type      = 0x40 +	// Dwarf4 +	DW_TAG_type_unit             = 0x41 +	DW_TAG_rvalue_reference_type = 0x42 +	DW_TAG_template_alias        = 0x43 + +	// User defined +	DW_TAG_lo_user = 0x4080 +	DW_TAG_hi_user = 0xffff +) + +// Table 19 +const ( +	DW_CHILDREN_no  = 0x00 +	DW_CHILDREN_yes = 0x01 +) + +// Not from the spec, but logically belongs here +const ( +	DW_CLS_ADDRESS = 0x01 + iota +	DW_CLS_BLOCK +	DW_CLS_CONSTANT +	DW_CLS_FLAG +	DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr +	DW_CLS_REFERENCE +	DW_CLS_ADDRLOC +	DW_CLS_STRING + +	// Go-specific internal hackery. +	DW_CLS_GO_TYPEREF +) + +// Table 20 +const ( +	DW_AT_sibling              = 0x01 // reference +	DW_AT_location             = 0x02 // block, loclistptr +	DW_AT_name                 = 0x03 // string +	DW_AT_ordering             = 0x09 // constant +	DW_AT_byte_size            = 0x0b // block, constant, reference +	DW_AT_bit_offset           = 0x0c // block, constant, reference +	DW_AT_bit_size             = 0x0d // block, constant, reference +	DW_AT_stmt_list            = 0x10 // lineptr +	DW_AT_low_pc               = 0x11 // address +	DW_AT_high_pc              = 0x12 // address +	DW_AT_language             = 0x13 // constant +	DW_AT_discr                = 0x15 // reference +	DW_AT_discr_value          = 0x16 // constant +	DW_AT_visibility           = 0x17 // constant +	DW_AT_import               = 0x18 // reference +	DW_AT_string_length        = 0x19 // block, loclistptr +	DW_AT_common_reference     = 0x1a // reference +	DW_AT_comp_dir             = 0x1b // string +	DW_AT_const_value          = 0x1c // block, constant, string +	DW_AT_containing_type      = 0x1d // reference +	DW_AT_default_value        = 0x1e // reference +	DW_AT_inline               = 0x20 // constant +	DW_AT_is_optional          = 0x21 // flag +	DW_AT_lower_bound          = 0x22 // block, constant, reference +	DW_AT_producer             = 0x25 // string +	DW_AT_prototyped           = 0x27 // flag +	DW_AT_return_addr          = 0x2a // block, loclistptr +	DW_AT_start_scope          = 0x2c // constant +	DW_AT_bit_stride           = 0x2e // constant +	DW_AT_upper_bound          = 0x2f // block, constant, reference +	DW_AT_abstract_origin      = 0x31 // reference +	DW_AT_accessibility        = 0x32 // constant +	DW_AT_address_class        = 0x33 // constant +	DW_AT_artificial           = 0x34 // flag +	DW_AT_base_types           = 0x35 // reference +	DW_AT_calling_convention   = 0x36 // constant +	DW_AT_count                = 0x37 // block, constant, reference +	DW_AT_data_member_location = 0x38 // block, constant, loclistptr +	DW_AT_decl_column          = 0x39 // constant +	DW_AT_decl_file            = 0x3a // constant +	DW_AT_decl_line            = 0x3b // constant +	DW_AT_declaration          = 0x3c // flag +	DW_AT_discr_list           = 0x3d // block +	DW_AT_encoding             = 0x3e // constant +	DW_AT_external             = 0x3f // flag +	DW_AT_frame_base           = 0x40 // block, loclistptr +	DW_AT_friend               = 0x41 // reference +	DW_AT_identifier_case      = 0x42 // constant +	DW_AT_macro_info           = 0x43 // macptr +	DW_AT_namelist_item        = 0x44 // block +	DW_AT_priority             = 0x45 // reference +	DW_AT_segment              = 0x46 // block, loclistptr +	DW_AT_specification        = 0x47 // reference +	DW_AT_static_link          = 0x48 // block, loclistptr +	DW_AT_type                 = 0x49 // reference +	DW_AT_use_location         = 0x4a // block, loclistptr +	DW_AT_variable_parameter   = 0x4b // flag +	DW_AT_virtuality           = 0x4c // constant +	DW_AT_vtable_elem_location = 0x4d // block, loclistptr +	// Dwarf3 +	DW_AT_allocated      = 0x4e // block, constant, reference +	DW_AT_associated     = 0x4f // block, constant, reference +	DW_AT_data_location  = 0x50 // block +	DW_AT_byte_stride    = 0x51 // block, constant, reference +	DW_AT_entry_pc       = 0x52 // address +	DW_AT_use_UTF8       = 0x53 // flag +	DW_AT_extension      = 0x54 // reference +	DW_AT_ranges         = 0x55 // rangelistptr +	DW_AT_trampoline     = 0x56 // address, flag, reference, string +	DW_AT_call_column    = 0x57 // constant +	DW_AT_call_file      = 0x58 // constant +	DW_AT_call_line      = 0x59 // constant +	DW_AT_description    = 0x5a // string +	DW_AT_binary_scale   = 0x5b // constant +	DW_AT_decimal_scale  = 0x5c // constant +	DW_AT_small          = 0x5d // reference +	DW_AT_decimal_sign   = 0x5e // constant +	DW_AT_digit_count    = 0x5f // constant +	DW_AT_picture_string = 0x60 // string +	DW_AT_mutable        = 0x61 // flag +	DW_AT_threads_scaled = 0x62 // flag +	DW_AT_explicit       = 0x63 // flag +	DW_AT_object_pointer = 0x64 // reference +	DW_AT_endianity      = 0x65 // constant +	DW_AT_elemental      = 0x66 // flag +	DW_AT_pure           = 0x67 // flag +	DW_AT_recursive      = 0x68 // flag + +	DW_AT_lo_user = 0x2000 // --- +	DW_AT_hi_user = 0x3fff // --- +) + +// Table 21 +const ( +	DW_FORM_addr      = 0x01 // address +	DW_FORM_block2    = 0x03 // block +	DW_FORM_block4    = 0x04 // block +	DW_FORM_data2     = 0x05 // constant +	DW_FORM_data4     = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr +	DW_FORM_data8     = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr +	DW_FORM_string    = 0x08 // string +	DW_FORM_block     = 0x09 // block +	DW_FORM_block1    = 0x0a // block +	DW_FORM_data1     = 0x0b // constant +	DW_FORM_flag      = 0x0c // flag +	DW_FORM_sdata     = 0x0d // constant +	DW_FORM_strp      = 0x0e // string +	DW_FORM_udata     = 0x0f // constant +	DW_FORM_ref_addr  = 0x10 // reference +	DW_FORM_ref1      = 0x11 // reference +	DW_FORM_ref2      = 0x12 // reference +	DW_FORM_ref4      = 0x13 // reference +	DW_FORM_ref8      = 0x14 // reference +	DW_FORM_ref_udata = 0x15 // reference +	DW_FORM_indirect  = 0x16 // (see Section 7.5.3) +	// Dwarf4 +	DW_FORM_sec_offset   = 0x17 // lineptr, loclistptr, macptr, rangelistptr +	DW_FORM_exprloc      = 0x18 // exprloc +	DW_FORM_flag_present = 0x19 // flag +	DW_FORM_ref_sig8     = 0x20 // reference +	// Pseudo-form: expanded to data4 on IOS, udata elsewhere. +	DW_FORM_udata_pseudo = 0x99 +) + +// Table 24 (#operands, notes) +const ( +	DW_OP_addr                = 0x03 // 1 constant address (size target specific) +	DW_OP_deref               = 0x06 // 0 +	DW_OP_const1u             = 0x08 // 1 1-byte constant +	DW_OP_const1s             = 0x09 // 1 1-byte constant +	DW_OP_const2u             = 0x0a // 1 2-byte constant +	DW_OP_const2s             = 0x0b // 1 2-byte constant +	DW_OP_const4u             = 0x0c // 1 4-byte constant +	DW_OP_const4s             = 0x0d // 1 4-byte constant +	DW_OP_const8u             = 0x0e // 1 8-byte constant +	DW_OP_const8s             = 0x0f // 1 8-byte constant +	DW_OP_constu              = 0x10 // 1 ULEB128 constant +	DW_OP_consts              = 0x11 // 1 SLEB128 constant +	DW_OP_dup                 = 0x12 // 0 +	DW_OP_drop                = 0x13 // 0 +	DW_OP_over                = 0x14 // 0 +	DW_OP_pick                = 0x15 // 1 1-byte stack index +	DW_OP_swap                = 0x16 // 0 +	DW_OP_rot                 = 0x17 // 0 +	DW_OP_xderef              = 0x18 // 0 +	DW_OP_abs                 = 0x19 // 0 +	DW_OP_and                 = 0x1a // 0 +	DW_OP_div                 = 0x1b // 0 +	DW_OP_minus               = 0x1c // 0 +	DW_OP_mod                 = 0x1d // 0 +	DW_OP_mul                 = 0x1e // 0 +	DW_OP_neg                 = 0x1f // 0 +	DW_OP_not                 = 0x20 // 0 +	DW_OP_or                  = 0x21 // 0 +	DW_OP_plus                = 0x22 // 0 +	DW_OP_plus_uconst         = 0x23 // 1 ULEB128 addend +	DW_OP_shl                 = 0x24 // 0 +	DW_OP_shr                 = 0x25 // 0 +	DW_OP_shra                = 0x26 // 0 +	DW_OP_xor                 = 0x27 // 0 +	DW_OP_skip                = 0x2f // 1 signed 2-byte constant +	DW_OP_bra                 = 0x28 // 1 signed 2-byte constant +	DW_OP_eq                  = 0x29 // 0 +	DW_OP_ge                  = 0x2a // 0 +	DW_OP_gt                  = 0x2b // 0 +	DW_OP_le                  = 0x2c // 0 +	DW_OP_lt                  = 0x2d // 0 +	DW_OP_ne                  = 0x2e // 0 +	DW_OP_lit0                = 0x30 // 0 ... +	DW_OP_lit31               = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal) +	DW_OP_reg0                = 0x50 // 0 .. +	DW_OP_reg31               = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum) +	DW_OP_breg0               = 0x70 // 1 ... +	DW_OP_breg31              = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum) +	DW_OP_regx                = 0x90 // 1 ULEB128 register +	DW_OP_fbreg               = 0x91 // 1 SLEB128 offset +	DW_OP_bregx               = 0x92 // 2 ULEB128 register followed by SLEB128 offset +	DW_OP_piece               = 0x93 // 1 ULEB128 size of piece addressed +	DW_OP_deref_size          = 0x94 // 1 1-byte size of data retrieved +	DW_OP_xderef_size         = 0x95 // 1 1-byte size of data retrieved +	DW_OP_nop                 = 0x96 // 0 +	DW_OP_push_object_address = 0x97 // 0 +	DW_OP_call2               = 0x98 // 1 2-byte offset of DIE +	DW_OP_call4               = 0x99 // 1 4-byte offset of DIE +	DW_OP_call_ref            = 0x9a // 1 4- or 8-byte offset of DIE +	DW_OP_form_tls_address    = 0x9b // 0 +	DW_OP_call_frame_cfa      = 0x9c // 0 +	DW_OP_bit_piece           = 0x9d // 2 +	DW_OP_lo_user             = 0xe0 +	DW_OP_hi_user             = 0xff +) + +// Table 25 +const ( +	DW_ATE_address         = 0x01 +	DW_ATE_boolean         = 0x02 +	DW_ATE_complex_float   = 0x03 +	DW_ATE_float           = 0x04 +	DW_ATE_signed          = 0x05 +	DW_ATE_signed_char     = 0x06 +	DW_ATE_unsigned        = 0x07 +	DW_ATE_unsigned_char   = 0x08 +	DW_ATE_imaginary_float = 0x09 +	DW_ATE_packed_decimal  = 0x0a +	DW_ATE_numeric_string  = 0x0b +	DW_ATE_edited          = 0x0c +	DW_ATE_signed_fixed    = 0x0d +	DW_ATE_unsigned_fixed  = 0x0e +	DW_ATE_decimal_float   = 0x0f +	DW_ATE_lo_user         = 0x80 +	DW_ATE_hi_user         = 0xff +) + +// Table 26 +const ( +	DW_DS_unsigned           = 0x01 +	DW_DS_leading_overpunch  = 0x02 +	DW_DS_trailing_overpunch = 0x03 +	DW_DS_leading_separate   = 0x04 +	DW_DS_trailing_separate  = 0x05 +) + +// Table 27 +const ( +	DW_END_default = 0x00 +	DW_END_big     = 0x01 +	DW_END_little  = 0x02 +	DW_END_lo_user = 0x40 +	DW_END_hi_user = 0xff +) + +// Table 28 +const ( +	DW_ACCESS_public    = 0x01 +	DW_ACCESS_protected = 0x02 +	DW_ACCESS_private   = 0x03 +) + +// Table 29 +const ( +	DW_VIS_local     = 0x01 +	DW_VIS_exported  = 0x02 +	DW_VIS_qualified = 0x03 +) + +// Table 30 +const ( +	DW_VIRTUALITY_none         = 0x00 +	DW_VIRTUALITY_virtual      = 0x01 +	DW_VIRTUALITY_pure_virtual = 0x02 +) + +// Table 31 +const ( +	DW_LANG_C89         = 0x0001 +	DW_LANG_C           = 0x0002 +	DW_LANG_Ada83       = 0x0003 +	DW_LANG_C_plus_plus = 0x0004 +	DW_LANG_Cobol74     = 0x0005 +	DW_LANG_Cobol85     = 0x0006 +	DW_LANG_Fortran77   = 0x0007 +	DW_LANG_Fortran90   = 0x0008 +	DW_LANG_Pascal83    = 0x0009 +	DW_LANG_Modula2     = 0x000a +	// Dwarf3 +	DW_LANG_Java           = 0x000b +	DW_LANG_C99            = 0x000c +	DW_LANG_Ada95          = 0x000d +	DW_LANG_Fortran95      = 0x000e +	DW_LANG_PLI            = 0x000f +	DW_LANG_ObjC           = 0x0010 +	DW_LANG_ObjC_plus_plus = 0x0011 +	DW_LANG_UPC            = 0x0012 +	DW_LANG_D              = 0x0013 +	// Dwarf4 +	DW_LANG_Python = 0x0014 +	// Dwarf5 +	DW_LANG_Go = 0x0016 + +	DW_LANG_lo_user = 0x8000 +	DW_LANG_hi_user = 0xffff +) + +// Table 32 +const ( +	DW_ID_case_sensitive   = 0x00 +	DW_ID_up_case          = 0x01 +	DW_ID_down_case        = 0x02 +	DW_ID_case_insensitive = 0x03 +) + +// Table 33 +const ( +	DW_CC_normal  = 0x01 +	DW_CC_program = 0x02 +	DW_CC_nocall  = 0x03 +	DW_CC_lo_user = 0x40 +	DW_CC_hi_user = 0xff +) + +// Table 34 +const ( +	DW_INL_not_inlined          = 0x00 +	DW_INL_inlined              = 0x01 +	DW_INL_declared_not_inlined = 0x02 +	DW_INL_declared_inlined     = 0x03 +) + +// Table 35 +const ( +	DW_ORD_row_major = 0x00 +	DW_ORD_col_major = 0x01 +) + +// Table 36 +const ( +	DW_DSC_label = 0x00 +	DW_DSC_range = 0x01 +) + +// Table 37 +const ( +	DW_LNS_copy             = 0x01 +	DW_LNS_advance_pc       = 0x02 +	DW_LNS_advance_line     = 0x03 +	DW_LNS_set_file         = 0x04 +	DW_LNS_set_column       = 0x05 +	DW_LNS_negate_stmt      = 0x06 +	DW_LNS_set_basic_block  = 0x07 +	DW_LNS_const_add_pc     = 0x08 +	DW_LNS_fixed_advance_pc = 0x09 +	// Dwarf3 +	DW_LNS_set_prologue_end   = 0x0a +	DW_LNS_set_epilogue_begin = 0x0b +	DW_LNS_set_isa            = 0x0c +) + +// Table 38 +const ( +	DW_LNE_end_sequence = 0x01 +	DW_LNE_set_address  = 0x02 +	DW_LNE_define_file  = 0x03 +	DW_LNE_lo_user      = 0x80 +	DW_LNE_hi_user      = 0xff +) + +// Table 39 +const ( +	DW_MACINFO_define     = 0x01 +	DW_MACINFO_undef      = 0x02 +	DW_MACINFO_start_file = 0x03 +	DW_MACINFO_end_file   = 0x04 +	DW_MACINFO_vendor_ext = 0xff +) + +// Table 40. +const ( +	// operand,... +	DW_CFA_nop              = 0x00 +	DW_CFA_set_loc          = 0x01 // address +	DW_CFA_advance_loc1     = 0x02 // 1-byte delta +	DW_CFA_advance_loc2     = 0x03 // 2-byte delta +	DW_CFA_advance_loc4     = 0x04 // 4-byte delta +	DW_CFA_offset_extended  = 0x05 // ULEB128 register, ULEB128 offset +	DW_CFA_restore_extended = 0x06 // ULEB128 register +	DW_CFA_undefined        = 0x07 // ULEB128 register +	DW_CFA_same_value       = 0x08 // ULEB128 register +	DW_CFA_register         = 0x09 // ULEB128 register, ULEB128 register +	DW_CFA_remember_state   = 0x0a +	DW_CFA_restore_state    = 0x0b + +	DW_CFA_def_cfa            = 0x0c // ULEB128 register, ULEB128 offset +	DW_CFA_def_cfa_register   = 0x0d // ULEB128 register +	DW_CFA_def_cfa_offset     = 0x0e // ULEB128 offset +	DW_CFA_def_cfa_expression = 0x0f // BLOCK +	DW_CFA_expression         = 0x10 // ULEB128 register, BLOCK +	DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset +	DW_CFA_def_cfa_sf         = 0x12 // ULEB128 register, SLEB128 offset +	DW_CFA_def_cfa_offset_sf  = 0x13 // SLEB128 offset +	DW_CFA_val_offset         = 0x14 // ULEB128, ULEB128 +	DW_CFA_val_offset_sf      = 0x15 // ULEB128, SLEB128 +	DW_CFA_val_expression     = 0x16 // ULEB128, BLOCK + +	DW_CFA_lo_user = 0x1c +	DW_CFA_hi_user = 0x3f + +	// Opcodes that take an addend operand. +	DW_CFA_advance_loc = 0x1 << 6 // +delta +	DW_CFA_offset      = 0x2 << 6 // +register (ULEB128 offset) +	DW_CFA_restore     = 0x3 << 6 // +register +) | 
