mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	proc: added fake runtime.curg variable
This commit is contained in:
		| @ -54,7 +54,9 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) { | |||||||
| 	case *ast.SelectorExpr: // <expression>.<identifier> | 	case *ast.SelectorExpr: // <expression>.<identifier> | ||||||
| 		// try to interpret the selector as a package variable | 		// try to interpret the selector as a package variable | ||||||
| 		if maybePkg, ok := node.X.(*ast.Ident); ok { | 		if maybePkg, ok := node.X.(*ast.Ident); ok { | ||||||
| 			if v, err := scope.packageVarAddr(maybePkg.Name + "." + node.Sel.Name); err == nil { | 			if maybePkg.Name == "runtime" && node.Sel.Name == "curg" { | ||||||
|  | 				return scope.Thread.getGVariable() | ||||||
|  | 			} else if v, err := scope.packageVarAddr(maybePkg.Name + "." + node.Sel.Name); err == nil { | ||||||
| 				return v, nil | 				return v, nil | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -497,7 +497,11 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) { | |||||||
| 	allgptr := binary.LittleEndian.Uint64(faddr) | 	allgptr := binary.LittleEndian.Uint64(faddr) | ||||||
|  |  | ||||||
| 	for i := uint64(0); i < allglen; i++ { | 	for i := uint64(0); i < allglen; i++ { | ||||||
| 		g, err := parseG(dbp.CurrentThread, allgptr+(i*uint64(dbp.arch.PtrSize())), true) | 		gvar, err := dbp.CurrentThread.newGVariable(uintptr(allgptr+(i*uint64(dbp.arch.PtrSize()))), true) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		g, err := gvar.parseG() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package proc | package proc | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"debug/dwarf" | ||||||
| 	"debug/gosym" | 	"debug/gosym" | ||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @ -247,6 +248,48 @@ func (thread *Thread) SetPC(pc uint64) error { | |||||||
| 	return regs.SetPC(thread, pc) | 	return regs.SetPC(thread, pc) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (thread *Thread) getGVariable() (*Variable, error) { | ||||||
|  | 	regs, err := thread.Registers() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if thread.dbp.arch.GStructOffset() == 0 { | ||||||
|  | 		// GetG was called through SwitchThread / updateThreadList during initialization | ||||||
|  | 		// thread.dbp.arch isn't setup yet (it needs a CurrentThread to read global variables from) | ||||||
|  | 		return nil, fmt.Errorf("g struct offset not initialized") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+thread.dbp.arch.GStructOffset()), thread.dbp.arch.PtrSize()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	gaddr := uintptr(binary.LittleEndian.Uint64(gaddrbs)) | ||||||
|  | 	 | ||||||
|  | 	// On Windows, the value at TLS()+GStructOffset() is a  | ||||||
|  | 	// pointer to the G struct. | ||||||
|  | 	needsDeref := runtime.GOOS == "windows" | ||||||
|  |  | ||||||
|  | 	return thread.newGVariable(gaddr, needsDeref) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (thread *Thread) newGVariable(gaddr uintptr, deref bool) (*Variable, error) { | ||||||
|  | 	typ, err := thread.dbp.findType("runtime.g") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	name := "" | ||||||
|  |  | ||||||
|  | 	if deref { | ||||||
|  | 		typ = &dwarf.PtrType{dwarf.CommonType{int64(thread.dbp.arch.PtrSize()), ""}, typ} | ||||||
|  | 	} else { | ||||||
|  | 		name = "runtime.curg" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return thread.newVariable(name, gaddr, typ), nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // GetG returns information on the G (goroutine) that is executing on this thread. | // GetG returns information on the G (goroutine) that is executing on this thread. | ||||||
| // | // | ||||||
| // The G structure for a thread is stored in thread local storage. Here we simply | // The G structure for a thread is stored in thread local storage. Here we simply | ||||||
| @ -262,26 +305,12 @@ func (thread *Thread) SetPC(pc uint64) error { | |||||||
| // In order to get around all this craziness, we read the address of the G structure for | // In order to get around all this craziness, we read the address of the G structure for | ||||||
| // the current thread from the thread local storage area. | // the current thread from the thread local storage area. | ||||||
| func (thread *Thread) GetG() (g *G, err error) { | func (thread *Thread) GetG() (g *G, err error) { | ||||||
| 	regs, err := thread.Registers() | 	gaddr, err := thread.getGVariable() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	if thread.dbp.arch.GStructOffset() == 0 { |  | ||||||
| 		// GetG was called through SwitchThread / updateThreadList during initialization |  | ||||||
| 		// thread.dbp.arch isn't setup yet (it needs a CurrentThread to read global variables from) |  | ||||||
| 		return nil, fmt.Errorf("g struct offset not initialized") |  | ||||||
| 	} |  | ||||||
| 	gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+thread.dbp.arch.GStructOffset()), thread.dbp.arch.PtrSize()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	gaddr := binary.LittleEndian.Uint64(gaddrbs) |  | ||||||
|  |  | ||||||
| 	// On Windows, the value at TLS()+GStructOffset() is a  | 	g, err = gaddr.parseG() | ||||||
| 	// pointer to the G struct. |  | ||||||
| 	needsDeref := runtime.GOOS == "windows" |  | ||||||
| 	 |  | ||||||
| 	g, err = parseG(thread, gaddr, needsDeref) |  | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		g.thread = thread | 		g.thread = thread | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -143,6 +143,10 @@ func (scope *EvalScope) newVariable(name string, addr uintptr, dwarfType dwarf.T | |||||||
| 	return newVariable(name, addr, dwarfType, scope.Thread.dbp, scope.Thread) | 	return newVariable(name, addr, dwarfType, scope.Thread.dbp, scope.Thread) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (t *Thread) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { | ||||||
|  | 	return newVariable(name, addr, dwarfType, t.dbp, t) | ||||||
|  | } | ||||||
|  |  | ||||||
| func (v *Variable) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { | func (v *Variable) newVariable(name string, addr uintptr, dwarfType dwarf.Type) *Variable { | ||||||
| 	return newVariable(name, addr, dwarfType, v.dbp, v.mem) | 	return newVariable(name, addr, dwarfType, v.dbp, v.mem) | ||||||
| } | } | ||||||
| @ -338,32 +342,40 @@ func (ng NoGError) Error() string { | |||||||
| 	return fmt.Sprintf("no G executing on thread %d", ng.tid) | 	return fmt.Sprintf("no G executing on thread %d", ng.tid) | ||||||
| } | } | ||||||
|  |  | ||||||
| func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | func (gvar *Variable) parseG() (*G, error) { | ||||||
| 	initialInstructions := make([]byte, thread.dbp.arch.PtrSize()+1) | 	mem := gvar.mem | ||||||
|  | 	dbp := gvar.dbp | ||||||
|  | 	gaddr := uint64(gvar.Addr) | ||||||
|  | 	_, deref := gvar.RealType.(*dwarf.PtrType) | ||||||
|  |  | ||||||
|  | 	initialInstructions := make([]byte, dbp.arch.PtrSize()+1) | ||||||
| 	initialInstructions[0] = op.DW_OP_addr | 	initialInstructions[0] = op.DW_OP_addr | ||||||
| 	binary.LittleEndian.PutUint64(initialInstructions[1:], gaddr) | 	binary.LittleEndian.PutUint64(initialInstructions[1:], gaddr) | ||||||
| 	if deref { | 	if deref { | ||||||
| 		gaddrbytes, err := thread.readMemory(uintptr(gaddr), thread.dbp.arch.PtrSize()) | 		gaddrbytes, err := mem.readMemory(uintptr(gaddr), dbp.arch.PtrSize()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("error derefing *G %s", err) | 			return nil, fmt.Errorf("error derefing *G %s", err) | ||||||
| 		} | 		} | ||||||
| 		initialInstructions = append([]byte{op.DW_OP_addr}, gaddrbytes...) | 		initialInstructions = append([]byte{op.DW_OP_addr}, gaddrbytes...) | ||||||
| 		gaddr = binary.LittleEndian.Uint64(gaddrbytes) | 		gaddr = binary.LittleEndian.Uint64(gaddrbytes) | ||||||
| 		if gaddr == 0 { | 		if gaddr == 0 { | ||||||
| 			return nil, NoGError{tid: thread.ID} | 			id := 0 | ||||||
|  | 			if thread, ok := mem.(*Thread); ok { | ||||||
|  | 				id = thread.ID | ||||||
|  | 			} | ||||||
|  | 			return nil, NoGError{tid: id} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	rdr := thread.dbp.DwarfReader() | 	rdr := dbp.DwarfReader() | ||||||
| 	rdr.Seek(0) | 	rdr.Seek(0) | ||||||
| 	entry, err := rdr.SeekToTypeNamed("runtime.g") | 	entry, err := rdr.SeekToTypeNamed("runtime.g") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var mem memoryReadWriter = thread | 	if gtype, err := dbp.dwarf.Type(entry.Offset); err == nil { | ||||||
| 	if gtype, err := thread.dbp.dwarf.Type(entry.Offset); err == nil { | 		mem = cacheMemory(mem, uintptr(gaddr), int(gtype.Size())) | ||||||
| 		mem = cacheMemory(thread, uintptr(gaddr), int(gtype.Size())) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Parse defer | 	// Parse defer | ||||||
| @ -373,7 +385,7 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | |||||||
| 	} | 	} | ||||||
| 	var deferPC uint64 | 	var deferPC uint64 | ||||||
| 	// Dereference *defer pointer | 	// Dereference *defer pointer | ||||||
| 	deferAddrBytes, err := mem.readMemory(uintptr(deferAddr), thread.dbp.arch.PtrSize()) | 	deferAddrBytes, err := mem.readMemory(uintptr(deferAddr), dbp.arch.PtrSize()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("error derefing defer %s", err) | 		return nil, fmt.Errorf("error derefing defer %s", err) | ||||||
| 	} | 	} | ||||||
| @ -412,7 +424,7 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	pc, err := readUintRaw(mem, uintptr(schedAddr+uint64(thread.dbp.arch.PtrSize())), 8) | 	pc, err := readUintRaw(mem, uintptr(schedAddr+uint64(dbp.arch.PtrSize())), 8) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -436,7 +448,7 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	waitreason, _, err := readString(mem, thread.dbp.arch, uintptr(waitReasonAddr)) | 	waitreason, _, err := readString(mem, dbp.arch, uintptr(waitReasonAddr)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -450,7 +462,7 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	f, l, fn := thread.dbp.goSymTable.PCToLine(pc) | 	f, l, fn := dbp.goSymTable.PCToLine(pc) | ||||||
| 	g := &G{ | 	g := &G{ | ||||||
| 		ID:         int(goid), | 		ID:         int(goid), | ||||||
| 		GoPC:       gopc, | 		GoPC:       gopc, | ||||||
| @ -460,7 +472,7 @@ func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) { | |||||||
| 		WaitReason: waitreason, | 		WaitReason: waitreason, | ||||||
| 		DeferPC:    deferPC, | 		DeferPC:    deferPC, | ||||||
| 		Status:     atomicStatus, | 		Status:     atomicStatus, | ||||||
| 		dbp:        thread.dbp, | 		dbp:        dbp, | ||||||
| 	} | 	} | ||||||
| 	return g, nil | 	return g, nil | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 aarzilli
					aarzilli