pkg/proc: Refactor Disassemble
This commit is contained in:
parent
583d335ffe
commit
9963458d77
@ -24,39 +24,24 @@ const (
|
||||
GoFlavour
|
||||
)
|
||||
|
||||
// Disassemble disassembles target memory between startPC and endPC, marking
|
||||
// Disassemble disassembles target memory between startAddr and endAddr, marking
|
||||
// the current instruction being executed in goroutine g.
|
||||
// If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble will evaluate the argument of the CALL instruction using the thread's registers
|
||||
// Be aware that the Bytes field of each returned instruction is a slice of a larger array of size endPC - startPC
|
||||
func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, error) {
|
||||
if _, err := dbp.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if g == nil {
|
||||
ct := dbp.CurrentThread()
|
||||
regs, _ := ct.Registers(false)
|
||||
return disassemble(ct, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC, false)
|
||||
}
|
||||
|
||||
var regs Registers
|
||||
var mem MemoryReadWriter = dbp.CurrentThread()
|
||||
if g.Thread != nil {
|
||||
mem = g.Thread
|
||||
regs, _ = g.Thread.Registers(false)
|
||||
}
|
||||
|
||||
return disassemble(mem, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC, false)
|
||||
// If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble
|
||||
// will evaluate the argument of the CALL instruction using the thread's registers.
|
||||
// Be aware that the Bytes field of each returned instruction is a slice of a larger array of size startAddr - endAddr.
|
||||
func Disassemble(mem MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startAddr, endAddr uint64) ([]AsmInstruction, error) {
|
||||
return disassemble(mem, regs, breakpoints, bi, startAddr, endAddr, false)
|
||||
}
|
||||
|
||||
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startPC, endPC uint64, singleInstr bool) ([]AsmInstruction, error) {
|
||||
mem := make([]byte, int(endPC-startPC))
|
||||
_, err := memrw.ReadMemory(mem, uintptr(startPC))
|
||||
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startAddr, endAddr uint64, singleInstr bool) ([]AsmInstruction, error) {
|
||||
mem := make([]byte, int(endAddr-startAddr))
|
||||
_, err := memrw.ReadMemory(mem, uintptr(startAddr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := make([]AsmInstruction, 0, len(mem)/15)
|
||||
pc := startPC
|
||||
pc := startAddr
|
||||
|
||||
var curpc uint64
|
||||
if regs != nil {
|
||||
|
@ -115,33 +115,6 @@ func FindFunctionLocation(p Process, funcName string, lineOffset int) (uint64, e
|
||||
return breakAddr, err
|
||||
}
|
||||
|
||||
// FunctionReturnLocations will return a list of addresses corresponding
|
||||
// to 'ret' or 'call runtime.deferreturn'.
|
||||
func FunctionReturnLocations(p Process, funcName string) ([]uint64, error) {
|
||||
const deferReturn = "runtime.deferreturn"
|
||||
|
||||
g := p.SelectedGoroutine()
|
||||
fn, ok := p.BinInfo().LookupFunc[funcName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to find function %s", funcName)
|
||||
}
|
||||
|
||||
instructions, err := Disassemble(p, g, fn.Entry, fn.End)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addrs []uint64
|
||||
for _, instruction := range instructions {
|
||||
if instruction.IsRet() {
|
||||
addrs = append(addrs, instruction.Loc.PC)
|
||||
}
|
||||
}
|
||||
addrs = append(addrs, findDeferReturnCalls(instructions)...)
|
||||
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
// Next continues execution until the next source line.
|
||||
func Next(dbp Process) (err error) {
|
||||
if _, err := dbp.Valid(); err != nil {
|
||||
|
@ -2545,7 +2545,7 @@ func TestStepOnCallPtrInstr(t *testing.T) {
|
||||
regs, err := p.CurrentThread().Registers(false)
|
||||
assertNoError(err, t, "Registers()")
|
||||
pc := regs.PC()
|
||||
text, err := proc.Disassemble(p, nil, pc, pc+maxInstructionLength)
|
||||
text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+maxInstructionLength)
|
||||
assertNoError(err, t, "Disassemble()")
|
||||
if text[0].IsCall() {
|
||||
found = true
|
||||
@ -3629,7 +3629,8 @@ func TestIssue1145(t *testing.T) {
|
||||
func TestDisassembleGlobalVars(t *testing.T) {
|
||||
withTestProcess("teststepconcurrent", t, func(p proc.Process, fixture protest.Fixture) {
|
||||
mainfn := p.BinInfo().LookupFunc["main.main"]
|
||||
text, err := proc.Disassemble(p, nil, mainfn.Entry, mainfn.End)
|
||||
regs, _ := p.CurrentThread().Registers(false)
|
||||
text, err := proc.Disassemble(p.CurrentThread(), regs, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End)
|
||||
assertNoError(err, t, "Disassemble")
|
||||
found := false
|
||||
for i := range text {
|
||||
|
@ -225,7 +225,7 @@ func next(dbp Process, stepInto, inlinedStepOut bool) error {
|
||||
}
|
||||
|
||||
if !csource {
|
||||
deferreturns := findDeferReturnCalls(text)
|
||||
deferreturns := FindDeferReturnCalls(text)
|
||||
|
||||
// Set breakpoint on the most recently deferred function (if any)
|
||||
var deferpc uint64
|
||||
@ -325,7 +325,7 @@ func next(dbp Process, stepInto, inlinedStepOut bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func findDeferReturnCalls(text []AsmInstruction) []uint64 {
|
||||
func FindDeferReturnCalls(text []AsmInstruction) []uint64 {
|
||||
const deferreturn = "runtime.deferreturn"
|
||||
deferreturns := []uint64{}
|
||||
|
||||
|
@ -218,12 +218,42 @@ func (d *Debugger) LastModified() time.Time {
|
||||
return d.target.BinInfo().LastModified()
|
||||
}
|
||||
|
||||
const deferReturn = "runtime.deferreturn"
|
||||
|
||||
// FunctionReturnLocations returns all return locations
|
||||
// for the given function. See the documentation for the
|
||||
// function of the same name within the `proc` package for
|
||||
// more information.
|
||||
// for the given function, a list of addresses corresponding
|
||||
// to 'ret' or 'call runtime.deferreturn'.
|
||||
func (d *Debugger) FunctionReturnLocations(fnName string) ([]uint64, error) {
|
||||
return proc.FunctionReturnLocations(d.target, fnName)
|
||||
var (
|
||||
p = d.target
|
||||
g = p.SelectedGoroutine()
|
||||
)
|
||||
|
||||
fn, ok := p.BinInfo().LookupFunc[fnName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to find function %s", fnName)
|
||||
}
|
||||
|
||||
var regs proc.Registers
|
||||
var mem proc.MemoryReadWriter = p.CurrentThread()
|
||||
if g.Thread != nil {
|
||||
mem = g.Thread
|
||||
regs, _ = g.Thread.Registers(false)
|
||||
}
|
||||
instructions, err := proc.Disassemble(mem, regs, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addrs []uint64
|
||||
for _, instruction := range instructions {
|
||||
if instruction.IsRet() {
|
||||
addrs = append(addrs, instruction.Loc.PC)
|
||||
}
|
||||
}
|
||||
addrs = append(addrs, proc.FindDeferReturnCalls(instructions)...)
|
||||
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
// Detach detaches from the target process.
|
||||
@ -1121,9 +1151,9 @@ func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Locat
|
||||
return locs, err
|
||||
}
|
||||
|
||||
// Disassemble code between startPC and endPC
|
||||
// if endPC == 0 it will find the function containing startPC and disassemble the whole function
|
||||
func (d *Debugger) Disassemble(scope api.EvalScope, startPC, endPC uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
||||
// Disassemble code between startPC and endPC.
|
||||
// if endPC == 0 it will find the function containing startPC and disassemble the whole function.
|
||||
func (d *Debugger) Disassemble(goroutineID int, addr1, addr2 uint64, flavour api.AssemblyFlavour) (api.AsmInstructions, error) {
|
||||
d.processMutex.Lock()
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
@ -1131,21 +1161,27 @@ func (d *Debugger) Disassemble(scope api.EvalScope, startPC, endPC uint64, flavo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if endPC == 0 {
|
||||
_, _, fn := d.target.BinInfo().PCToLine(startPC)
|
||||
if addr2 == 0 {
|
||||
_, _, fn := d.target.BinInfo().PCToLine(addr1)
|
||||
if fn == nil {
|
||||
return nil, fmt.Errorf("Address 0x%x does not belong to any function", startPC)
|
||||
return nil, fmt.Errorf("address %#x does not belong to any function", addr1)
|
||||
}
|
||||
startPC = fn.Entry
|
||||
endPC = fn.End
|
||||
addr1 = fn.Entry
|
||||
addr2 = fn.End
|
||||
}
|
||||
|
||||
g, err := proc.FindGoroutine(d.target, scope.GoroutineID)
|
||||
g, err := proc.FindGoroutine(d.target, goroutineID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
insts, err := proc.Disassemble(d.target, g, startPC, endPC)
|
||||
var regs proc.Registers
|
||||
var mem proc.MemoryReadWriter = d.target.CurrentThread()
|
||||
if g.Thread != nil {
|
||||
mem = g.Thread
|
||||
regs, _ = g.Thread.Registers(false)
|
||||
}
|
||||
insts, err := proc.Disassemble(mem, regs, d.target.Breakpoints(), d.target.BinInfo(), addr1, addr2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -317,6 +317,6 @@ type DisassembleRequest struct {
|
||||
|
||||
func (c *RPCServer) Disassemble(args DisassembleRequest, answer *api.AsmInstructions) error {
|
||||
var err error
|
||||
*answer, err = c.debugger.Disassemble(args.Scope, args.StartPC, args.EndPC, args.Flavour)
|
||||
*answer, err = c.debugger.Disassemble(args.Scope.GoroutineID, args.StartPC, args.EndPC, args.Flavour)
|
||||
return err
|
||||
}
|
||||
|
@ -607,7 +607,7 @@ type DisassembleOut struct {
|
||||
// Disassemble will also try to calculate the destination address of an absolute indirect CALL if it happens to be the instruction the selected goroutine is stopped at.
|
||||
func (c *RPCServer) Disassemble(arg DisassembleIn, out *DisassembleOut) error {
|
||||
var err error
|
||||
out.Disassemble, err = c.debugger.Disassemble(arg.Scope, arg.StartPC, arg.EndPC, arg.Flavour)
|
||||
out.Disassemble, err = c.debugger.Disassemble(arg.Scope.GoroutineID, arg.StartPC, arg.EndPC, arg.Flavour)
|
||||
return err
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user