pkg/proc: fix StepBreakpoint handling

StepBreakpoints are set on CALL instructions, when they are hit we
disassemble the current instruction, figure out the destination address
and set a breakpoint after the prologue of the called function.

In order to disassemble the current instruction we disassemble the area
of memory starting from PC and going to PC+15 (because 15 bytes is the
maximum length of one instruction on AMD64). This means that we won't
just disassemble one instruction but also a few instructions following
it ending with one truncated instruction.

This usually works fine but sometimes the disassembler will panic with
an array out of bounds error when trying to disassemble a truncated
instruction. To avoid this problem this commit changes the funciton
disassemble to take one extra parameter, singleInstr, when singleInstr
is set disassemble will quit after disassembling a single instruction.
This commit is contained in:
aarzilli 2017-11-06 18:34:59 +01:00 committed by Alessandro Arzilli
parent 5f0f77f414
commit bc86c662a6
4 changed files with 9 additions and 6 deletions

@ -27,7 +27,7 @@ func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, er
if g == nil {
ct := dbp.CurrentThread()
regs, _ := ct.Registers(false)
return disassemble(ct, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC)
return disassemble(ct, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC, false)
}
var regs Registers
@ -37,10 +37,10 @@ func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, er
regs, _ = g.Thread.Registers(false)
}
return disassemble(mem, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC)
return disassemble(mem, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC, false)
}
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startPC, endPC uint64) ([]AsmInstruction, error) {
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))
if err != nil {
@ -77,6 +77,9 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *Breakpoint
pc++
mem = mem[1:]
}
if singleInstr {
break
}
}
return r, nil
}

@ -144,7 +144,7 @@ func FirstPCAfterPrologue(p Process, fn *Function, sameline bool) (uint64, error
var mem MemoryReadWriter = p.CurrentThread()
breakpoints := p.Breakpoints()
bi := p.BinInfo()
text, err := disassemble(mem, nil, breakpoints, bi, fn.Entry, fn.End)
text, err := disassemble(mem, nil, breakpoints, bi, fn.Entry, fn.End, false)
if err != nil {
return fn.Entry, err
}

@ -136,7 +136,7 @@ func Continue(dbp Process) error {
return err
}
pc := regs.PC()
text, err := disassemble(curthread, regs, dbp.Breakpoints(), dbp.BinInfo(), pc, pc+maxInstructionLength)
text, err := disassemble(curthread, regs, dbp.Breakpoints(), dbp.BinInfo(), pc, pc+maxInstructionLength, true)
if err != nil {
return err
}

@ -131,7 +131,7 @@ func next(dbp Process, stepInto bool) error {
}
}
text, err := disassemble(thread, regs, dbp.Breakpoints(), dbp.BinInfo(), topframe.Current.Fn.Entry, topframe.Current.Fn.End)
text, err := disassemble(thread, regs, dbp.Breakpoints(), dbp.BinInfo(), topframe.Current.Fn.Entry, topframe.Current.Fn.End, false)
if err != nil && stepInto {
return err
}