mirror of
https://github.com/beego/bee.git
synced 2025-07-06 09:50:18 +00:00
Use Delve v0.12.1 instead of master
This commit is contained in:
183
vendor/github.com/derekparker/delve/proc/disasm_amd64.go
generated
vendored
Normal file
183
vendor/github.com/derekparker/delve/proc/disasm_amd64.go
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"debug/gosym"
|
||||
"encoding/binary"
|
||||
"rsc.io/x86/x86asm"
|
||||
)
|
||||
|
||||
var maxInstructionLength uint64 = 15
|
||||
|
||||
type ArchInst x86asm.Inst
|
||||
|
||||
func asmDecode(mem []byte, pc uint64) (*ArchInst, error) {
|
||||
inst, err := x86asm.Decode(mem, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patchPCRel(pc, &inst)
|
||||
r := ArchInst(inst)
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func (inst *ArchInst) Size() int {
|
||||
return inst.Len
|
||||
}
|
||||
|
||||
// converts PC relative arguments to absolute addresses
|
||||
func patchPCRel(pc uint64, inst *x86asm.Inst) {
|
||||
for i := range inst.Args {
|
||||
rel, isrel := inst.Args[i].(x86asm.Rel)
|
||||
if isrel {
|
||||
inst.Args[i] = x86asm.Imm(int64(pc) + int64(rel) + int64(inst.Len))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (inst *AsmInstruction) Text(flavour AssemblyFlavour) string {
|
||||
if inst.Inst == nil {
|
||||
return "?"
|
||||
}
|
||||
|
||||
var text string
|
||||
|
||||
switch flavour {
|
||||
case GNUFlavour:
|
||||
text = x86asm.GNUSyntax(x86asm.Inst(*inst.Inst))
|
||||
case IntelFlavour:
|
||||
fallthrough
|
||||
default:
|
||||
text = x86asm.IntelSyntax(x86asm.Inst(*inst.Inst))
|
||||
}
|
||||
|
||||
if inst.IsCall() && inst.DestLoc != nil && inst.DestLoc.Fn != nil {
|
||||
text += " " + inst.DestLoc.Fn.Name
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
func (inst *AsmInstruction) IsCall() bool {
|
||||
return inst.Inst.Op == x86asm.CALL || inst.Inst.Op == x86asm.LCALL
|
||||
}
|
||||
|
||||
func (thread *Thread) resolveCallArg(inst *ArchInst, currentGoroutine bool, regs Registers) *Location {
|
||||
if inst.Op != x86asm.CALL && inst.Op != x86asm.LCALL {
|
||||
return nil
|
||||
}
|
||||
|
||||
var pc uint64
|
||||
var err error
|
||||
|
||||
switch arg := inst.Args[0].(type) {
|
||||
case x86asm.Imm:
|
||||
pc = uint64(arg)
|
||||
case x86asm.Reg:
|
||||
if !currentGoroutine || regs == nil {
|
||||
return nil
|
||||
}
|
||||
pc, err = regs.Get(int(arg))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
case x86asm.Mem:
|
||||
if !currentGoroutine || regs == nil {
|
||||
return nil
|
||||
}
|
||||
if arg.Segment != 0 {
|
||||
return nil
|
||||
}
|
||||
regs, err := thread.Registers(false)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
base, err1 := regs.Get(int(arg.Base))
|
||||
index, err2 := regs.Get(int(arg.Index))
|
||||
if err1 != nil || err2 != nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp)
|
||||
//TODO: should this always be 64 bits instead of inst.MemBytes?
|
||||
pcbytes, err := thread.readMemory(addr, inst.MemBytes)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pc = binary.LittleEndian.Uint64(pcbytes)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
file, line, fn := thread.dbp.PCToLine(pc)
|
||||
if fn == nil {
|
||||
return nil
|
||||
}
|
||||
return &Location{PC: pc, File: file, Line: line, Fn: fn}
|
||||
}
|
||||
|
||||
type instrseq []x86asm.Op
|
||||
|
||||
// Possible stacksplit prologues are inserted by stacksplit in
|
||||
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
|
||||
// The stacksplit prologue will always begin with loading curg in CX, this
|
||||
// instruction is added by load_g_cx in the same file and is either 1 or 2
|
||||
// MOVs.
|
||||
var prologues []instrseq
|
||||
|
||||
func init() {
|
||||
var tinyStacksplit = instrseq{x86asm.CMP, x86asm.JBE}
|
||||
var smallStacksplit = instrseq{x86asm.LEA, x86asm.CMP, x86asm.JBE}
|
||||
var bigStacksplit = instrseq{x86asm.MOV, x86asm.CMP, x86asm.JE, x86asm.LEA, x86asm.SUB, x86asm.CMP, x86asm.JBE}
|
||||
var unixGetG = instrseq{x86asm.MOV}
|
||||
var windowsGetG = instrseq{x86asm.MOV, x86asm.MOV}
|
||||
|
||||
prologues = make([]instrseq, 0, 2*3)
|
||||
for _, getG := range []instrseq{unixGetG, windowsGetG} {
|
||||
for _, stacksplit := range []instrseq{tinyStacksplit, smallStacksplit, bigStacksplit} {
|
||||
prologue := make(instrseq, 0, len(getG)+len(stacksplit))
|
||||
prologue = append(prologue, getG...)
|
||||
prologue = append(prologue, stacksplit...)
|
||||
prologues = append(prologues, prologue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FirstPCAfterPrologue returns the address of the first instruction after the prologue for function fn
|
||||
// If sameline is set FirstPCAfterPrologue will always return an address associated with the same line as fn.Entry
|
||||
func (dbp *Process) FirstPCAfterPrologue(fn *gosym.Func, sameline bool) (uint64, error) {
|
||||
text, err := dbp.CurrentThread.Disassemble(fn.Entry, fn.End, false)
|
||||
if err != nil {
|
||||
return fn.Entry, err
|
||||
}
|
||||
|
||||
if len(text) <= 0 {
|
||||
return fn.Entry, nil
|
||||
}
|
||||
|
||||
for _, prologue := range prologues {
|
||||
if len(prologue) >= len(text) {
|
||||
continue
|
||||
}
|
||||
if checkPrologue(text, prologue) {
|
||||
r := &text[len(prologue)]
|
||||
if sameline {
|
||||
if r.Loc.Line != text[0].Loc.Line {
|
||||
return fn.Entry, nil
|
||||
}
|
||||
}
|
||||
return r.Loc.PC, nil
|
||||
}
|
||||
}
|
||||
|
||||
return fn.Entry, nil
|
||||
}
|
||||
|
||||
func checkPrologue(s []AsmInstruction, prologuePattern instrseq) bool {
|
||||
line := s[0].Loc.Line
|
||||
for i, op := range prologuePattern {
|
||||
if s[i].Inst.Op != op || s[i].Loc.Line != line {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user