2016-02-06 06:00:48 +00:00
package proc
2017-10-26 11:37:19 +00:00
import "sort"
2016-02-06 06:00:48 +00:00
type AsmInstruction struct {
Loc Location
DestLoc * Location
Bytes [ ] byte
Breakpoint bool
AtPC bool
Inst * ArchInst
}
type AssemblyFlavour int
const (
GNUFlavour = AssemblyFlavour ( iota )
IntelFlavour
2017-10-26 11:37:19 +00:00
GoFlavour
2016-02-06 06:00:48 +00:00
)
2017-02-15 13:41:03 +00:00
// Disassemble disassembles target memory between startPC and endPC, 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
2017-04-21 07:50:38 +00:00
func Disassemble ( dbp Process , g * G , startPC , endPC uint64 ) ( [ ] AsmInstruction , error ) {
2017-07-26 22:57:47 +00:00
if dbp . Exited ( ) {
return nil , & ProcessExitedError { Pid : dbp . Pid ( ) }
}
2017-04-13 23:19:57 +00:00
if g == nil {
2017-02-15 13:41:03 +00:00
ct := dbp . CurrentThread ( )
regs , _ := ct . Registers ( false )
2017-11-06 17:34:59 +00:00
return disassemble ( ct , regs , dbp . Breakpoints ( ) , dbp . BinInfo ( ) , startPC , endPC , false )
2017-04-13 23:19:57 +00:00
}
var regs Registers
2017-04-21 06:55:53 +00:00
var mem MemoryReadWriter = dbp . CurrentThread ( )
if g . Thread != nil {
mem = g . Thread
regs , _ = g . Thread . Registers ( false )
2017-04-13 23:19:57 +00:00
}
2017-11-06 17:34:59 +00:00
return disassemble ( mem , regs , dbp . Breakpoints ( ) , dbp . BinInfo ( ) , startPC , endPC , false )
2017-04-13 23:19:57 +00:00
}
2017-11-06 17:34:59 +00:00
func disassemble ( memrw MemoryReadWriter , regs Registers , breakpoints * BreakpointMap , bi * BinaryInfo , startPC , endPC uint64 , singleInstr bool ) ( [ ] AsmInstruction , error ) {
2017-04-18 14:24:45 +00:00
mem := make ( [ ] byte , int ( endPC - startPC ) )
_ , err := memrw . ReadMemory ( mem , uintptr ( startPC ) )
2016-02-06 06:00:48 +00:00
if err != nil {
return nil , err
}
r := make ( [ ] AsmInstruction , 0 , len ( mem ) / 15 )
pc := startPC
var curpc uint64
2017-04-13 23:19:57 +00:00
if regs != nil {
curpc = regs . PC ( )
2016-02-06 06:00:48 +00:00
}
for len ( mem ) > 0 {
2017-09-24 13:00:55 +00:00
bp , atbp := breakpoints . M [ pc ]
2016-02-06 06:00:48 +00:00
if atbp {
for i := range bp . OriginalData {
mem [ i ] = bp . OriginalData [ i ]
}
}
2017-04-13 23:19:57 +00:00
file , line , fn := bi . PCToLine ( pc )
2016-02-06 06:00:48 +00:00
loc := Location { PC : pc , File : file , Line : line , Fn : fn }
inst , err := asmDecode ( mem , pc )
if err == nil {
2017-04-13 23:19:57 +00:00
atpc := ( regs != nil ) && ( curpc == pc )
destloc := resolveCallArg ( inst , atpc , regs , memrw , bi )
2016-02-06 06:00:48 +00:00
r = append ( r , AsmInstruction { Loc : loc , DestLoc : destloc , Bytes : mem [ : inst . Len ] , Breakpoint : atbp , AtPC : atpc , Inst : inst } )
pc += uint64 ( inst . Size ( ) )
mem = mem [ inst . Size ( ) : ]
} else {
r = append ( r , AsmInstruction { Loc : loc , Bytes : mem [ : 1 ] , Breakpoint : atbp , Inst : nil } )
pc ++
mem = mem [ 1 : ]
}
2017-11-06 17:34:59 +00:00
if singleInstr {
break
}
2016-02-06 06:00:48 +00:00
}
return r , nil
}
2017-10-26 11:37:19 +00:00
// Looks up symbol (either functions or global variables) at address addr.
// Used by disassembly formatter.
func ( bi * BinaryInfo ) symLookup ( addr uint64 ) ( string , uint64 ) {
fn := bi . PCToFunc ( addr )
if fn != nil {
if fn . Entry == addr {
// only report the function name if it's the exact address because it's
// easier to read the absolute address than function_name+offset.
return fn . Name , fn . Entry
}
return "" , 0
}
i := sort . Search ( len ( bi . packageVars ) , func ( i int ) bool {
return bi . packageVars [ i ] . addr >= addr
} )
if i >= len ( bi . packageVars ) {
return "" , 0
}
if bi . packageVars [ i ] . addr > addr {
// report previous variable + offset if i-th variable starts after addr
i --
}
if i > 0 {
return bi . packageVars [ i ] . name , bi . packageVars [ i ] . addr
}
return "" , 0
}