mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	Refactor: replace dwarf.Reader with wrapped reader
This commit is contained in:
		| @ -63,27 +63,21 @@ func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) { | ||||
| 	return nil, fmt.Errorf("unable to find function context") | ||||
| } | ||||
|  | ||||
| // 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() { | ||||
| // Returns the address for the named entry. | ||||
| func (reader *Reader) AddrFor(name string) (uint64, error) { | ||||
| 	entry, err := reader.FindEntryNamed(name, false) | ||||
| 	if err != nil { | ||||
| 			return nil, err | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 		n, ok := entry.Val(dwarf.AttrName).(string) | ||||
| 	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte) | ||||
| 	if !ok { | ||||
| 			continue | ||||
| 		return 0, fmt.Errorf("type assertion failed") | ||||
| 	} | ||||
|  | ||||
| 		if n == name { | ||||
| 			return entry, nil | ||||
| 	addr, err := op.ExecuteStackProgram(0, instructions) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	} | ||||
|  | ||||
| 	return nil, errors.New("no type entry found") | ||||
| 	return uint64(addr), nil | ||||
| } | ||||
|  | ||||
| // 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") | ||||
| } | ||||
|  | ||||
| // 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. | ||||
| func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) { | ||||
| 	for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() { | ||||
|  | ||||
| @ -394,15 +394,21 @@ func (dbp *DebuggedProcess) SwitchThread(tid int) error { | ||||
| func (dbp *DebuggedProcess) GoroutinesInfo() ([]*G, error) { | ||||
| 	var ( | ||||
| 		allg []*G | ||||
| 		reader = dbp.dwarf.Reader() | ||||
| 		rdr  = dbp.DwarfReader() | ||||
| 	) | ||||
|  | ||||
| 	allglen, err := allglenval(dbp, reader) | ||||
| 	addr, err := rdr.AddrFor("runtime.allglen") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	reader.Seek(0) | ||||
| 	allgentryaddr, err := addressFor(dbp, "runtime.allg", reader) | ||||
| 	allglenBytes, err := dbp.CurrentThread.readMemory(uintptr(addr), 8) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	allglen := binary.LittleEndian.Uint64(allglenBytes) | ||||
|  | ||||
| 	rdr.Seek(0) | ||||
| 	allgentryaddr, err := rdr.AddrFor("runtime.allg") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @ -68,172 +68,6 @@ func (g *G) chanRecvReturnAddr(dbp *DebuggedProcess) (uint64, error) { | ||||
| 	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 { | ||||
| 	tid int | ||||
| } | ||||
| @ -319,45 +153,6 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) { | ||||
| 	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. | ||||
| func (thread *ThreadContext) EvalSymbol(name string) (*Variable, error) { | ||||
| 	pc, err := thread.PC() | ||||
| @ -433,45 +228,8 @@ func (thread *ThreadContext) PackageVariables() ([]*Variable, error) { | ||||
| 	return vars, nil | ||||
| } | ||||
|  | ||||
| func findDwarfEntry(name string, reader *dwarf.Reader, 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 (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, reader *reader.Reader, memberName string) (*Variable, error) { | ||||
| 	parentAddr, err := thread.extractVariableDataAddress(parentEntry, reader) | ||||
| func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) { | ||||
| 	parentAddr, err := thread.extractVariableDataAddress(parentEntry, rdr) | ||||
| 	if err != nil { | ||||
| 		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 | ||||
| 	_, err = reader.SeekToType(parentEntry, true, true) | ||||
| 	_, err = rdr.SeekToType(parentEntry, true, true) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// 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 { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @ -505,7 +263,7 @@ func (thread *ThreadContext) evaluateStructMember(parentEntry *dwarf.Entry, read | ||||
| 				return nil, fmt.Errorf("%s is nil", parentName) | ||||
| 			} | ||||
|  | ||||
| 			memberInstr, err := instructionsForEntry(memberEntry) | ||||
| 			memberInstr, err := rdr.InstructionsForEntry(memberEntry) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @ -597,8 +355,8 @@ func (thread *ThreadContext) executeStackProgram(instructions []byte) (int64, er | ||||
| } | ||||
|  | ||||
| // Extracts the address of a variable, dereferencing any pointers | ||||
| func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, reader *reader.Reader) (int64, error) { | ||||
| 	instructions, err := instructionsForEntry(entry) | ||||
| func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, rdr *reader.Reader) (int64, error) { | ||||
| 	instructions, err := rdr.InstructionsForEntry(entry) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| @ -609,7 +367,7 @@ func (thread *ThreadContext) extractVariableDataAddress(entry *dwarf.Entry, read | ||||
| 	} | ||||
|  | ||||
| 	// 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 { | ||||
| 			return 0, err | ||||
| 		} | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Derek Parker
					Derek Parker