proc: replace Thread.Location method with a function (#3972)

Replaces the Thread.Location method with a ThreadLocation function. All
backends implemented the Location method exactly the same way, this
change deduplicates it.
This commit is contained in:
Alessandro Arzilli
2025-04-07 20:45:17 +02:00
committed by GitHub
parent cc4343bff6
commit 193f21e49b
12 changed files with 40 additions and 67 deletions

View File

@ -319,18 +319,6 @@ func (t *thread) ProcessMemory() proc.MemoryReadWriter {
return t.p
}
// Location returns the location of this thread based on
// the value of the instruction pointer register.
func (t *thread) Location() (*proc.Location, error) {
regs, err := t.Registers()
if err != nil {
return nil, err
}
pc := regs.PC()
f, l, fn := t.p.bi.PCToLine(pc)
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}
// Breakpoint returns the current breakpoint this thread is stopped at.
// For core files this always returns an empty BreakpointState struct, as
// there are no breakpoints when debugging core files.

View File

@ -815,7 +815,7 @@ func funcCallStep(callScope *EvalScope, stack *evalStack, thread Thread) bool {
regval := bi.Arch.RegistersToDwarfRegisters(0, regs).Uint64Val(fncall.protocolReg)
if logflags.FnCall() {
loc, _ := thread.Location()
loc, _ := ThreadLocation(thread)
var pc uint64
var fnname string
if loc != nil {
@ -1151,7 +1151,7 @@ func callInjectionProtocol(t *Target, trapthread Thread, threads []Thread) (done
t.currentThread = currentThread
}()
for _, thread := range threads {
loc, err := thread.Location()
loc, err := ThreadLocation(thread)
if err != nil {
continue
}

View File

@ -1523,22 +1523,6 @@ func (t *gdbThread) ProcessMemory() proc.MemoryReadWriter {
return t.p
}
// Location returns the current location of this thread.
func (t *gdbThread) Location() (*proc.Location, error) {
regs, err := t.Registers()
if err != nil {
return nil, err
}
if pcreg, ok := regs.(*gdbRegisters).regs[regs.(*gdbRegisters).regnames.PC]; !ok {
t.p.conn.log.Errorf("thread %d could not find RIP register", t.ID)
} else if len(pcreg.value) < t.p.bi.Arch.PtrSize() {
t.p.conn.log.Errorf("thread %d bad length for RIP register: %d", t.ID, len(pcreg.value))
}
pc := regs.PC()
f, l, fn := t.p.bi.PCToLine(pc)
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}
// Breakpoint returns the current active breakpoint for this thread.
func (t *gdbThread) Breakpoint() *proc.BreakpointState {
return &t.CurrentBreakpoint

View File

@ -73,7 +73,7 @@ func TestRestartAfterExit(t *testing.T) {
p := grp.Selected
setFunctionBreakpoint(p, t, "main.main")
assertNoError(grp.Continue(), t, "Continue")
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location()")
err = grp.Continue()
if !errors.As(err, &proc.ErrProcessExited{}) {
@ -83,7 +83,7 @@ func TestRestartAfterExit(t *testing.T) {
assertNoError(grp.Restart(""), t, "Restart")
assertNoError(grp.Continue(), t, "Continue (after restart)")
loc2, err := p.CurrentThread().Location()
loc2, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location() (after restart)")
if loc2.Line != loc.Line {
t.Fatalf("stopped at %d (expected %d)", loc2.Line, loc.Line)
@ -101,13 +101,13 @@ func TestRestartDuringStop(t *testing.T) {
p := grp.Selected
setFunctionBreakpoint(p, t, "main.main")
assertNoError(grp.Continue(), t, "Continue")
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location()")
assertNoError(grp.Restart(""), t, "Restart")
assertNoError(grp.Continue(), t, "Continue (after restart)")
loc2, err := p.CurrentThread().Location()
loc2, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location() (after restart)")
if loc2.Line != loc.Line {
t.Fatalf("stopped at %d (expected %d)", loc2.Line, loc.Line)
@ -143,7 +143,7 @@ func TestReverseBreakpointCounts(t *testing.T) {
p := grp.Selected
endbp := setFileBreakpoint(p, t, fixture, 28)
assertNoError(grp.Continue(), t, "Continue()")
loc, _ := p.CurrentThread().Location()
loc, _ := proc.ThreadLocation(p.CurrentThread())
if loc.PC != endbp.Addr {
t.Fatalf("did not reach end of main.main function: %s:%d (%#x)", loc.File, loc.Line, loc.PC)
}
@ -156,7 +156,7 @@ func TestReverseBreakpointCounts(t *testing.T) {
countLoop:
for {
assertNoError(grp.Continue(), t, "Continue()")
loc, _ := p.CurrentThread().Location()
loc, _ := proc.ThreadLocation(p.CurrentThread())
switch loc.PC {
case startbp.Addr:
break countLoop
@ -188,7 +188,7 @@ func getPosition(grp *proc.TargetGroup, t *testing.T) (when string, loc *proc.Lo
var err error
when, err = grp.When()
assertNoError(err, t, "When")
loc, err = grp.Selected.CurrentThread().Location()
loc, err = proc.ThreadLocation(grp.Selected.CurrentThread())
assertNoError(err, t, "Location")
return
}

View File

@ -77,18 +77,6 @@ func (procgrp *processGroup) stepInstruction(t *nativeThread) (err error) {
return nil
}
// Location returns the threads location, including the file:line
// of the corresponding source code, the function we're in
// and the current instruction address.
func (t *nativeThread) Location() (*proc.Location, error) {
pc, err := t.PC()
if err != nil {
return nil, err
}
f, l, fn := t.dbp.bi.PCToLine(pc)
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}
// BinInfo returns information on the binary.
func (t *nativeThread) BinInfo() *proc.BinaryInfo {
return t.dbp.bi

View File

@ -1627,7 +1627,7 @@ func TestStepIntoFunction(t *testing.T) {
// Step into function
assertNoError(grp.Step(), t, "Step() returned an error")
// We should now be inside the function.
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
if err != nil {
t.Fatal(err)
}
@ -2462,7 +2462,7 @@ func TestNextInDeferReturn(t *testing.T) {
// point where the target program panics.
setFunctionBreakpoint(p, t, "main.sampleFunction")
for i := 0; i < 20; i++ {
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location()")
t.Logf("at %#x %s:%d", loc.PC, loc.File, loc.Line)
if loc.Fn != nil && loc.Fn.Name == "main.sampleFunction" {
@ -3184,7 +3184,7 @@ func TestIssue1008(t *testing.T) {
withTestProcess("cgostacktest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
setFunctionBreakpoint(p, t, "main.main")
assertNoError(grp.Continue(), t, "Continue()")
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "CurrentThread().Location()")
t.Logf("location %v\n", loc)
if !strings.HasSuffix(loc.File, "/main.go") {
@ -5176,7 +5176,7 @@ func TestFollowExec(t *testing.T) {
if grp.Selected.CurrentThread().Breakpoint().Breakpoint.LogicalID() != 1 {
t.Fatalf("wrong breakpoint %#v", grp.Selected.CurrentThread().Breakpoint().Breakpoint)
}
loc, err := grp.Selected.CurrentThread().Location()
loc, err := proc.ThreadLocation(grp.Selected.CurrentThread())
assertNoError(err, t, "Location")
if loc.Fn.Name != "main.traceme1" {
t.Fatalf("wrong stop location %#v", loc)
@ -5188,7 +5188,7 @@ func TestFollowExec(t *testing.T) {
if p.CurrentThread().Breakpoint().Breakpoint.LogicalID() != 3 {
t.Fatalf("wrong breakpoint %#v", p.CurrentThread().Breakpoint().Breakpoint)
}
loc, err := p.CurrentThread().Location()
loc, err := proc.ThreadLocation(p.CurrentThread())
assertNoError(err, t, "Location")
if loc.Fn.Name != "main.traceme3" {
t.Fatalf("wrong stop location %#v", loc)
@ -5208,7 +5208,7 @@ func TestFollowExec(t *testing.T) {
t.Fatalf("wrong breakpoint %#v", grp.Selected.CurrentThread().Breakpoint().Breakpoint)
}
pids[tgt.Pid()]++
loc, err := tgt.CurrentThread().Location()
loc, err := proc.ThreadLocation(tgt.CurrentThread())
assertNoError(err, t, "Location")
if loc.Fn.Name != "main.traceme2" {
t.Fatalf("wrong stop location %#v", loc)
@ -5268,7 +5268,7 @@ func TestStepShadowConcurrentBreakpoint(t *testing.T) {
for {
t.Logf("stop (%d %d):", stacktraceme1calls, stacktraceme2calls)
for _, th := range p.ThreadList() {
loc, _ := th.Location()
loc, _ := proc.ThreadLocation(th)
t.Logf("\t%s:%d\n", loc.File, loc.Line)
bp := th.Breakpoint().Breakpoint
if bp != nil && bp.Addr == break2.Addr {

View File

@ -444,7 +444,7 @@ func stepInstructionOut(grp *TargetGroup, dbp *Target, curthread Thread, fnname1
if err := grp.procgrp.StepInstruction(curthread.ThreadID()); err != nil {
return err
}
loc, err := curthread.Location()
loc, err := ThreadLocation(curthread)
var locFnName string
if loc.Fn != nil && !loc.Fn.cu.image.Stripped() {
locFnName = loc.Fn.Name
@ -995,7 +995,7 @@ func stepIntoCallback(curthread Thread, p *Target) (bool, error) {
}
var fn *Function
if loc, _ := curthread.Location(); loc != nil {
if loc, _ := ThreadLocation(curthread); loc != nil {
fn = loc.Fn
}
g, _ := GetG(curthread)
@ -1675,7 +1675,7 @@ func (t *Target) handleHardcodedBreakpoints(grp *TargetGroup, trapthread Thread,
continue
}
loc, err := thread.Location()
loc, err := ThreadLocation(thread)
if err != nil || loc.Fn == nil {
continue
}

View File

@ -8,7 +8,6 @@ import (
// Thread represents a thread.
type Thread interface {
Location() (*Location, error)
// Breakpoint will return the breakpoint that this thread is stopped at or
// nil if the thread is not stopped at any breakpoint.
Breakpoint() *BreakpointState
@ -103,3 +102,16 @@ func setClosureReg(thread Thread, newClosureReg uint64) error {
func setLR(thread Thread, newLR uint64) error {
return thread.SetReg(thread.BinInfo().Arch.LRRegNum, op.DwarfRegisterFromUint64(newLR))
}
// ThreadLocation returns the threads location, including the file:line
// of the corresponding source code, the function we're in
// and the current instruction address.
func ThreadLocation(thread Thread) (*Location, error) {
regs, err := thread.Registers()
if err != nil {
return nil, err
}
pc := regs.PC()
f, l, fn := thread.BinInfo().PCToLine(pc)
return &Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}

View File

@ -257,7 +257,8 @@ func GetG(thread Thread) (*G, error) {
if thread.Common().g != nil {
return thread.Common().g, nil
}
if loc, _ := thread.Location(); loc != nil && loc.Fn != nil && loc.Fn.Name == "runtime.clone" {
loc, _ := ThreadLocation(thread)
if loc != nil && loc.Fn != nil && loc.Fn.Name == "runtime.clone" {
// When threads are executing runtime.clone the value of TLS is unreliable.
return nil, nil
}
@ -296,7 +297,7 @@ func GetG(thread Thread) (*G, error) {
g.SystemStack = true
}
g.Thread = thread
if loc, err := thread.Location(); err == nil {
if err == nil {
g.CurrentLoc = *loc
}
thread.Common().g = g
@ -354,7 +355,7 @@ func GoroutinesInfo(dbp *Target, start, count int) ([]*G, int, error) {
continue
}
if thg, allocated := threadg[g.ID]; allocated {
loc, err := thg.Thread.Location()
loc, err := ThreadLocation(thg.Thread)
if err != nil {
return nil, -1, err
}

View File

@ -136,7 +136,7 @@ func doFuzzEvalExpressionSetup(f *testing.F) {
assertNoError(err, f, "Stacktrace")
mem := c.Memory()
loc, _ := c.CurrentThread().Location()
loc, _ := proc.ThreadLocation(c.CurrentThread())
tmem := &tracingMem{make(map[uint64]int), mem}
scope := &proc.EvalScope{Location: *loc, Regs: frames[0].Regs, Mem: tmem, BinInfo: c.BinInfo()}

View File

@ -97,7 +97,7 @@ func ConvertThread(th proc.Thread, bp *Breakpoint) *Thread {
gid int64
)
loc, err := th.Location()
loc, err := proc.ThreadLocation(th)
if err == nil {
pc = loc.PC
file = loc.File

View File

@ -1893,7 +1893,7 @@ func (d *Debugger) CurrentPackage() (string, error) {
if _, err := d.target.Valid(); err != nil {
return "", err
}
loc, err := d.target.Selected.CurrentThread().Location()
loc, err := proc.ThreadLocation(d.target.Selected.CurrentThread())
if err != nil {
return "", err
}
@ -2231,7 +2231,7 @@ func (d *Debugger) TargetGroup() *proc.TargetGroup {
}
func (d *Debugger) BuildID() string {
loc, err := d.target.Selected.CurrentThread().Location()
loc, err := proc.ThreadLocation(d.target.Selected.CurrentThread())
if err != nil {
return ""
}