mirror of
https://github.com/beego/bee.git
synced 2025-07-01 22:20:17 +00:00
Updated vendor
This commit is contained in:
446
vendor/github.com/go-delve/delve/pkg/dwarf/reader/reader.go
generated
vendored
Normal file
446
vendor/github.com/go-delve/delve/pkg/dwarf/reader/reader.go
generated
vendored
Normal file
@ -0,0 +1,446 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/op"
|
||||
)
|
||||
|
||||
type Reader struct {
|
||||
*dwarf.Reader
|
||||
depth int
|
||||
}
|
||||
|
||||
// New returns a reader for the specified dwarf data.
|
||||
func New(data *dwarf.Data) *Reader {
|
||||
return &Reader{data.Reader(), 0}
|
||||
}
|
||||
|
||||
// Seek moves the reader to an arbitrary offset.
|
||||
func (reader *Reader) Seek(off dwarf.Offset) {
|
||||
reader.depth = 0
|
||||
reader.Reader.Seek(off)
|
||||
}
|
||||
|
||||
// SeekToEntry moves the reader to an arbitrary entry.
|
||||
func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
|
||||
reader.Seek(entry.Offset)
|
||||
// Consume the current entry so .Next works as intended
|
||||
_, err := reader.Next()
|
||||
return err
|
||||
}
|
||||
|
||||
// SeekToFunctionEntry moves the reader to the function that includes the
|
||||
// specified program counter.
|
||||
func (reader *Reader) SeekToFunction(pc RelAddr) (*dwarf.Entry, error) {
|
||||
reader.Seek(0)
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag != dwarf.TagSubprogram {
|
||||
continue
|
||||
}
|
||||
|
||||
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if lowpc <= uint64(pc) && highpc > uint64(pc) {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to find function context")
|
||||
}
|
||||
|
||||
// Returns the address for the named entry.
|
||||
func (reader *Reader) AddrFor(name string, staticBase uint64) (uint64, error) {
|
||||
entry, err := reader.FindEntryNamed(name, false)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("type assertion failed")
|
||||
}
|
||||
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{StaticBase: staticBase}, instructions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(addr), nil
|
||||
}
|
||||
|
||||
// Returns the address for the named struct member. Expects the reader to be at the parent entry
|
||||
// or one of the parents children, thus does not seek to parent by itself.
|
||||
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
|
||||
for {
|
||||
entry, err := reader.NextMemberVariable()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if entry == nil {
|
||||
return 0, fmt.Errorf("nil entry for member named %s", member)
|
||||
}
|
||||
name, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || name != member {
|
||||
continue
|
||||
}
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
addr, _, err := op.ExecuteStackProgram(op.DwarfRegisters{}, append(initialInstructions, instructions...))
|
||||
return uint64(addr), err
|
||||
}
|
||||
}
|
||||
|
||||
var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types")
|
||||
|
||||
// SeekToType moves the reader to the type specified by the entry,
|
||||
// optionally resolving typedefs and pointer types. If the reader is set
|
||||
// to a struct type the NextMemberVariable call can be used to walk all member data.
|
||||
func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) {
|
||||
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("entry does not have a type attribute")
|
||||
}
|
||||
|
||||
// Seek to the first type offset
|
||||
reader.Seek(offset)
|
||||
|
||||
// Walk the types to the base
|
||||
for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset)
|
||||
if !ok {
|
||||
return typeEntry, nil
|
||||
}
|
||||
|
||||
reader.Seek(offset)
|
||||
}
|
||||
|
||||
return nil, TypeNotFoundErr
|
||||
}
|
||||
|
||||
func (reader *Reader) NextType() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch entry.Tag {
|
||||
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
||||
// If the reader is set to a struct type the NextMemberVariable call
|
||||
// can be used to walk all member data.
|
||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
||||
// Walk the types to the base
|
||||
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if n == name {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, TypeNotFoundErr
|
||||
}
|
||||
|
||||
// Finds the entry for 'name'.
|
||||
func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) {
|
||||
depth := 1
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Children {
|
||||
depth++
|
||||
}
|
||||
|
||||
if entry.Tag == 0 {
|
||||
depth--
|
||||
if depth <= 0 {
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
if member {
|
||||
if entry.Tag != dwarf.TagMember {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || n != name {
|
||||
continue
|
||||
}
|
||||
return entry, nil
|
||||
}
|
||||
return nil, fmt.Errorf("could not find symbol value for %s", name)
|
||||
}
|
||||
|
||||
func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) {
|
||||
entry, err := reader.FindEntryNamed(name, member)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var attr dwarf.Attr
|
||||
if member {
|
||||
attr = dwarf.AttrDataMemberLoc
|
||||
} else {
|
||||
attr = dwarf.AttrLocation
|
||||
}
|
||||
instr, ok := entry.Val(attr).([]byte)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid typecast for Dwarf instructions")
|
||||
}
|
||||
return instr, nil
|
||||
}
|
||||
|
||||
func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) {
|
||||
if entry.Tag == dwarf.TagMember {
|
||||
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("member data has no data member location attribute")
|
||||
}
|
||||
// clone slice to prevent stomping on the dwarf data
|
||||
return append([]byte{}, instructions...), nil
|
||||
}
|
||||
|
||||
// non-member
|
||||
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("entry has no location attribute")
|
||||
}
|
||||
|
||||
// clone slice to prevent stomping on the dwarf data
|
||||
return append([]byte{}, instructions...), nil
|
||||
}
|
||||
|
||||
// NextMemberVariable moves the reader to the next debug entry that describes a member variable and returns the entry.
|
||||
func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// All member variables will be at the same depth
|
||||
reader.SkipChildren()
|
||||
|
||||
// End of the current depth
|
||||
if entry.Tag == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagMember {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NextPackageVariable moves the reader to the next debug entry that describes a package variable.
|
||||
// Any TagVariable entry that is not inside a sub prgram entry and is marked external is considered a package variable.
|
||||
func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagVariable {
|
||||
ext, ok := entry.Val(dwarf.AttrExternal).(bool)
|
||||
if ok && ext {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore everything inside sub programs
|
||||
if entry.Tag == dwarf.TagSubprogram {
|
||||
reader.SkipChildren()
|
||||
}
|
||||
}
|
||||
|
||||
// No more items
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
|
||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry.Tag == dwarf.TagCompileUnit {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Entry represents a debug_info entry.
|
||||
// When calling Val, if the entry does not have the specified attribute, the
|
||||
// entry specified by DW_AT_abstract_origin will be searched recursively.
|
||||
type Entry interface {
|
||||
Val(dwarf.Attr) interface{}
|
||||
}
|
||||
|
||||
type compositeEntry []*dwarf.Entry
|
||||
|
||||
func (ce compositeEntry) Val(attr dwarf.Attr) interface{} {
|
||||
for _, e := range ce {
|
||||
if r := e.Val(attr); r != nil {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAbstractOrigin loads the entry corresponding to the
|
||||
// DW_AT_abstract_origin of entry and returns a combination of entry and its
|
||||
// abstract origin.
|
||||
func LoadAbstractOrigin(entry *dwarf.Entry, aordr *dwarf.Reader) (Entry, dwarf.Offset) {
|
||||
ao, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
|
||||
if !ok {
|
||||
return entry, entry.Offset
|
||||
}
|
||||
|
||||
r := []*dwarf.Entry{entry}
|
||||
|
||||
for {
|
||||
aordr.Seek(ao)
|
||||
e, _ := aordr.Next()
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
r = append(r, e)
|
||||
|
||||
ao, ok = e.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return compositeEntry(r), entry.Offset
|
||||
}
|
||||
|
||||
// InlineStackReader provides a way to read the stack of inlined calls at a
|
||||
// specified PC address.
|
||||
type InlineStackReader struct {
|
||||
dwarf *dwarf.Data
|
||||
reader *dwarf.Reader
|
||||
entry *dwarf.Entry
|
||||
depth int
|
||||
pc uint64
|
||||
err error
|
||||
}
|
||||
|
||||
// InlineStack returns an InlineStackReader for the specified function and
|
||||
// PC address.
|
||||
// If pc is 0 then all inlined calls will be returned.
|
||||
func InlineStack(dwarf *dwarf.Data, fnoff dwarf.Offset, pc RelAddr) *InlineStackReader {
|
||||
reader := dwarf.Reader()
|
||||
reader.Seek(fnoff)
|
||||
return &InlineStackReader{dwarf: dwarf, reader: reader, entry: nil, depth: 0, pc: uint64(pc)}
|
||||
}
|
||||
|
||||
// Next reads next inlined call in the stack, returns false if there aren't any.
|
||||
func (irdr *InlineStackReader) Next() bool {
|
||||
if irdr.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
irdr.entry, irdr.err = irdr.reader.Next()
|
||||
if irdr.entry == nil || irdr.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch irdr.entry.Tag {
|
||||
case 0:
|
||||
irdr.depth--
|
||||
if irdr.depth == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
case dwarf.TagLexDwarfBlock, dwarf.TagSubprogram, dwarf.TagInlinedSubroutine:
|
||||
var recur bool
|
||||
if irdr.pc != 0 {
|
||||
recur, irdr.err = entryRangesContains(irdr.dwarf, irdr.entry, irdr.pc)
|
||||
} else {
|
||||
recur = true
|
||||
}
|
||||
if recur {
|
||||
irdr.depth++
|
||||
if irdr.entry.Tag == dwarf.TagInlinedSubroutine {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if irdr.depth == 0 {
|
||||
return false
|
||||
}
|
||||
irdr.reader.SkipChildren()
|
||||
}
|
||||
|
||||
default:
|
||||
irdr.reader.SkipChildren()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Entry returns the DIE for the current inlined call.
|
||||
func (irdr *InlineStackReader) Entry() *dwarf.Entry {
|
||||
return irdr.entry
|
||||
}
|
||||
|
||||
// Err returns an error, if any was encountered.
|
||||
func (irdr *InlineStackReader) Err() error {
|
||||
return irdr.err
|
||||
}
|
||||
|
||||
// SkipChildren skips all children of the current inlined call.
|
||||
func (irdr *InlineStackReader) SkipChildren() {
|
||||
irdr.reader.SkipChildren()
|
||||
}
|
114
vendor/github.com/go-delve/delve/pkg/dwarf/reader/variables.go
generated
vendored
Normal file
114
vendor/github.com/go-delve/delve/pkg/dwarf/reader/variables.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"debug/dwarf"
|
||||
)
|
||||
|
||||
// RelAddr is an address relative to the static base. For normal executables
|
||||
// this is just a normal memory address, for PIE it's a relative address.
|
||||
type RelAddr uint64
|
||||
|
||||
func ToRelAddr(addr uint64, staticBase uint64) RelAddr {
|
||||
return RelAddr(addr - staticBase)
|
||||
}
|
||||
|
||||
// VariableReader provides a way of reading the local variables and formal
|
||||
// parameters of a function that are visible at the specified PC address.
|
||||
type VariableReader struct {
|
||||
dwarf *dwarf.Data
|
||||
reader *dwarf.Reader
|
||||
entry *dwarf.Entry
|
||||
depth int
|
||||
onlyVisible bool
|
||||
pc uint64
|
||||
line int
|
||||
err error
|
||||
}
|
||||
|
||||
// Variables returns a VariableReader for the function or lexical block at off.
|
||||
// If onlyVisible is true only variables visible at pc will be returned by
|
||||
// the VariableReader.
|
||||
func Variables(dwarf *dwarf.Data, off dwarf.Offset, pc RelAddr, line int, onlyVisible bool) *VariableReader {
|
||||
reader := dwarf.Reader()
|
||||
reader.Seek(off)
|
||||
return &VariableReader{dwarf: dwarf, reader: reader, entry: nil, depth: 0, onlyVisible: onlyVisible, pc: uint64(pc), line: line, err: nil}
|
||||
}
|
||||
|
||||
// Next reads the next variable entry, returns false if there aren't any.
|
||||
func (vrdr *VariableReader) Next() bool {
|
||||
if vrdr.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for {
|
||||
vrdr.entry, vrdr.err = vrdr.reader.Next()
|
||||
if vrdr.entry == nil || vrdr.err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch vrdr.entry.Tag {
|
||||
case 0:
|
||||
vrdr.depth--
|
||||
if vrdr.depth == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
case dwarf.TagLexDwarfBlock, dwarf.TagSubprogram, dwarf.TagInlinedSubroutine:
|
||||
recur := true
|
||||
if vrdr.onlyVisible {
|
||||
recur, vrdr.err = entryRangesContains(vrdr.dwarf, vrdr.entry, vrdr.pc)
|
||||
if vrdr.err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if recur && vrdr.entry.Children {
|
||||
vrdr.depth++
|
||||
} else {
|
||||
if vrdr.depth == 0 {
|
||||
return false
|
||||
}
|
||||
vrdr.reader.SkipChildren()
|
||||
}
|
||||
|
||||
default:
|
||||
if vrdr.depth == 0 {
|
||||
vrdr.err = errors.New("offset was not lexical block or subprogram")
|
||||
return false
|
||||
}
|
||||
if declLine, ok := vrdr.entry.Val(dwarf.AttrDeclLine).(int64); !ok || vrdr.line >= int(declLine) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func entryRangesContains(dwarf *dwarf.Data, entry *dwarf.Entry, pc uint64) (bool, error) {
|
||||
rngs, err := dwarf.Ranges(entry)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, rng := range rngs {
|
||||
if pc >= rng[0] && pc < rng[1] {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Entry returns the current variable entry.
|
||||
func (vrdr *VariableReader) Entry() *dwarf.Entry {
|
||||
return vrdr.entry
|
||||
}
|
||||
|
||||
// Depth returns the depth of the current scope
|
||||
func (vrdr *VariableReader) Depth() int {
|
||||
return vrdr.depth
|
||||
}
|
||||
|
||||
// Err returns the error if there was one.
|
||||
func (vrdr *VariableReader) Err() error {
|
||||
return vrdr.err
|
||||
}
|
Reference in New Issue
Block a user