Refactor: replace dwarf.Reader with wrapped reader
This commit is contained in:
parent
544f20992f
commit
2cfbc2937f
@ -63,27 +63,21 @@ func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
|
|||||||
return nil, fmt.Errorf("unable to find function context")
|
return nil, fmt.Errorf("unable to find function context")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SeekToTypeNamed moves the reader to the type specified by the name.
|
// Returns the address for the named entry.
|
||||||
// If the reader is set to a struct type the NextMemberVariable call
|
func (reader *Reader) AddrFor(name string) (uint64, error) {
|
||||||
// can be used to walk all member data.
|
entry, err := reader.FindEntryNamed(name, false)
|
||||||
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
|
if err != nil {
|
||||||
// Walk the types to the base
|
return 0, err
|
||||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n, ok := entry.Val(dwarf.AttrName).(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == name {
|
|
||||||
return entry, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
|
||||||
return nil, errors.New("no type entry found")
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("type assertion failed")
|
||||||
|
}
|
||||||
|
addr, err := op.ExecuteStackProgram(0, instructions)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return uint64(addr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the address for the named struct member.
|
// Returns the address for the named struct member.
|
||||||
@ -143,6 +137,105 @@ func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resol
|
|||||||
return nil, fmt.Errorf("no type entry found")
|
return nil, fmt.Errorf("no type entry found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.Next(); entry != nil; entry, err = reader.Next() {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n, ok := entry.Val(dwarf.AttrName).(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if n == name {
|
||||||
|
return entry, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("no type entry found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
// NextScopeVariable moves the reader to the next debug entry that describes a local variable and returns the entry.
|
// NextScopeVariable moves the reader to the next debug entry that describes a local variable and returns the entry.
|
||||||
func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) {
|
func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) {
|
||||||
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
|
||||||
|
|||||||
@ -393,16 +393,22 @@ func (dbp *DebuggedProcess) SwitchThread(tid int) error {
|
|||||||
// Delve cares about from the internal runtime G structure.
|
// Delve cares about from the internal runtime G structure.
|
||||||
func (dbp *DebuggedProcess) GoroutinesInfo() ([]*G, error) {
|
func (dbp *DebuggedProcess) GoroutinesInfo() ([]*G, error) {
|
||||||
var (
|
var (
|
||||||
allg []*G
|
allg []*G
|
||||||
reader = dbp.dwarf.Reader()
|
rdr = dbp.DwarfReader()
|
||||||
)
|
)
|
||||||
|
|
||||||
allglen, err := allglenval(dbp, reader)
|
addr, err := rdr.AddrFor("runtime.allglen")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reader.Seek(0)
|
allglenBytes, err := dbp.CurrentThread.readMemory(uintptr(addr), 8)
|
||||||
allgentryaddr, err := addressFor(dbp, "runtime.allg", reader)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
allglen := binary.LittleEndian.Uint64(allglenBytes)
|
||||||
|
|
||||||
|
rdr.Seek(0)
|
||||||
|
allgentryaddr, err := rdr.AddrFor("runtime.allg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,172 +68,6 @@ func (g *G) chanRecvReturnAddr(dbp *DebuggedProcess) (uint64, error) {
|
|||||||
return topLoc.addr, nil
|
return topLoc.addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses and returns select info on the internal M
|
|
||||||
// data structures used by the Go scheduler.
|
|
||||||
func (thread *ThreadContext) AllM() ([]*M, error) {
|
|
||||||
reader := thread.Process.dwarf.Reader()
|
|
||||||
|
|
||||||
allmaddr, err := parseAllMPtr(thread.Process, reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mptr, err := thread.readMemory(uintptr(allmaddr), thread.Process.arch.PtrSize())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m := binary.LittleEndian.Uint64(mptr)
|
|
||||||
if m == 0 {
|
|
||||||
return nil, fmt.Errorf("allm contains no M pointers")
|
|
||||||
}
|
|
||||||
|
|
||||||
procidInstructions, err := instructionsFor("procid", thread.Process, reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
spinningInstructions, err := instructionsFor("spinning", thread.Process, reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
alllinkInstructions, err := instructionsFor("alllink", thread.Process, reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
blockedInstructions, err := instructionsFor("blocked", thread.Process, reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
curgInstructions, err := instructionsFor("curg", thread.Process, reader, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var allm []*M
|
|
||||||
for {
|
|
||||||
// curg
|
|
||||||
curgAddr, err := executeMemberStackProgram(mptr, curgInstructions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
curgBytes, err := thread.readMemory(uintptr(curgAddr), thread.Process.arch.PtrSize())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read curg %#v %s", curgAddr, err)
|
|
||||||
}
|
|
||||||
curg := binary.LittleEndian.Uint64(curgBytes)
|
|
||||||
|
|
||||||
// procid
|
|
||||||
procidAddr, err := executeMemberStackProgram(mptr, procidInstructions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
procidBytes, err := thread.readMemory(uintptr(procidAddr), thread.Process.arch.PtrSize())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read procid %#v %s", procidAddr, err)
|
|
||||||
}
|
|
||||||
procid := binary.LittleEndian.Uint64(procidBytes)
|
|
||||||
|
|
||||||
// spinning
|
|
||||||
spinningAddr, err := executeMemberStackProgram(mptr, spinningInstructions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
spinBytes, err := thread.readMemory(uintptr(spinningAddr), 1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read spinning %#v %s", spinningAddr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// blocked
|
|
||||||
blockedAddr, err := executeMemberStackProgram(mptr, blockedInstructions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
blockBytes, err := thread.readMemory(uintptr(blockedAddr), 1)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read blocked %#v %s", blockedAddr, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
allm = append(allm, &M{
|
|
||||||
procid: int(procid),
|
|
||||||
blocked: blockBytes[0],
|
|
||||||
spinning: spinBytes[0],
|
|
||||||
curg: uintptr(curg),
|
|
||||||
})
|
|
||||||
|
|
||||||
// Follow the linked list
|
|
||||||
alllinkAddr, err := executeMemberStackProgram(mptr, alllinkInstructions)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mptr, err = thread.readMemory(uintptr(alllinkAddr), thread.Process.arch.PtrSize())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not read alllink %#v %s", alllinkAddr, err)
|
|
||||||
}
|
|
||||||
m = binary.LittleEndian.Uint64(mptr)
|
|
||||||
|
|
||||||
if m == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allm, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func instructionsFor(name string, dbp *DebuggedProcess, reader *dwarf.Reader, member bool) ([]byte, error) {
|
|
||||||
reader.Seek(0)
|
|
||||||
entry, err := findDwarfEntry(name, reader, member)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return instructionsForEntry(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func 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
|
|
||||||
}
|
|
||||||
|
|
||||||
func executeMemberStackProgram(base, instructions []byte) (uint64, error) {
|
|
||||||
parentInstructions := append([]byte{op.DW_OP_addr}, base...)
|
|
||||||
addr, err := op.ExecuteStackProgram(0, append(parentInstructions, instructions...))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint64(addr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseAllMPtr(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) {
|
|
||||||
entry, err := findDwarfEntry("runtime.allm", reader, 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(0, instructions)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint64(addr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type NoGError struct {
|
type NoGError struct {
|
||||||
tid int
|
tid int
|
||||||
}
|
}
|
||||||
@ -319,45 +153,6 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) {
|
|||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func allglenval(dbp *DebuggedProcess, reader *dwarf.Reader) (uint64, error) {
|
|
||||||
entry, err := findDwarfEntry("runtime.allglen", reader, 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(0, instructions)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
val, err := dbp.CurrentThread.readMemory(uintptr(addr), 8)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return binary.LittleEndian.Uint64(val), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addressFor(dbp *DebuggedProcess, name string, reader *dwarf.Reader) (uint64, error) {
|
|
||||||
entry, err := findDwarfEntry(name, reader, 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(0, instructions)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint64(addr), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the value of the named symbol.
|
// Returns the value of the named symbol.
|
||||||
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) {
|
||||||
pc, err := thread.PC()
|
pc, err := thread.PC()
|
||||||
@ -433,45 +228,8 @@ func (thread *ThreadContext) PackageVariables() ([]*Variable, error) {
|
|||||||
return vars, nil
|
return vars, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findDwarfEntry(name string, reader *dwarf.Reader, member bool) (*dwarf.Entry, error) {
|
func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) {
|
||||||
depth := 1
|
parentAddr, err := thread.extractVariableDataAddress(parentEntry, rdr)
|
||||||
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 (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, reader *reader.Reader, memberName string) (*Variable, error) {
|
|
||||||
parentAddr, err := thread.extractVariableDataAddress(parentEntry, reader)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -483,13 +241,13 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, read
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Seek reader to the type information so members can be iterated
|
// Seek reader to the type information so members can be iterated
|
||||||
_, err = reader.SeekToType(parentEntry, true, true)
|
_, err = rdr.SeekToType(parentEntry, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate to find member by name
|
// Iterate to find member by name
|
||||||
for memberEntry, err := reader.NextMemberVariable(); memberEntry != nil; memberEntry, err = reader.NextMemberVariable() {
|
for memberEntry, err := rdr.NextMemberVariable(); memberEntry != nil; memberEntry, err = rdr.NextMemberVariable() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -505,7 +263,7 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, read
|
|||||||
return nil, fmt.Errorf("%s is nil", parentName)
|
return nil, fmt.Errorf("%s is nil", parentName)
|
||||||
}
|
}
|
||||||
|
|
||||||
memberInstr, err := instructionsForEntry(memberEntry)
|
memberInstr, err := rdr.InstructionsForEntry(memberEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -597,8 +355,8 @@ func (thread *ThreadContext) executeStackProgram(instructions []byte) (int64, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extracts the address of a variable, dereferencing any pointers
|
// Extracts the address of a variable, dereferencing any pointers
|
||||||
func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, reader *reader.Reader) (int64, error) {
|
func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, rdr *reader.Reader) (int64, error) {
|
||||||
instructions, err := instructionsForEntry(entry)
|
instructions, err := rdr.InstructionsForEntry(entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -609,7 +367,7 @@ func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, read
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dereference pointers to get down the concrete type
|
// Dereference pointers to get down the concrete type
|
||||||
for typeEntry, err := reader.SeekToType(entry, true, false); typeEntry != nil; typeEntry, err = reader.SeekToType(typeEntry, true, false) {
|
for typeEntry, err := rdr.SeekToType(entry, true, false); typeEntry != nil; typeEntry, err = rdr.SeekToType(typeEntry, true, false) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user