mirror of
https://github.com/go-delve/delve.git
synced 2025-11-01 20:20:40 +08:00
dwarf/frame: detecting dwarf section endianness
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package frame
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
@ -25,6 +26,7 @@ type FrameDescriptionEntry struct {
|
||||
CIE *CommonInformationEntry
|
||||
Instructions []byte
|
||||
begin, end uint64
|
||||
order binary.ByteOrder
|
||||
}
|
||||
|
||||
// Returns whether or not the given address is within the
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package frame
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
@ -39,7 +40,7 @@ func BenchmarkFDEForPC(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
fdes := Parse(data)
|
||||
fdes := Parse(data, binary.BigEndian)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
// bench worst case, exhaustive search
|
||||
|
||||
@ -23,7 +23,7 @@ type parseContext struct {
|
||||
// Parse takes in data (a byte slice) and returns a slice of
|
||||
// commonInformationEntry structures. Each commonInformationEntry
|
||||
// has a slice of frameDescriptionEntry structures.
|
||||
func Parse(data []byte) FrameDescriptionEntries {
|
||||
func Parse(data []byte, order binary.ByteOrder) FrameDescriptionEntries {
|
||||
var (
|
||||
buf = bytes.NewBuffer(data)
|
||||
pctx = &parseContext{buf: buf, entries: NewFrameIndex()}
|
||||
@ -33,6 +33,10 @@ func Parse(data []byte) FrameDescriptionEntries {
|
||||
fn = fn(pctx)
|
||||
}
|
||||
|
||||
for i := range pctx.entries {
|
||||
pctx.entries[i].order = order
|
||||
}
|
||||
|
||||
return pctx.entries
|
||||
}
|
||||
|
||||
@ -100,3 +104,22 @@ func parseCIE(ctx *parseContext) parsefunc {
|
||||
|
||||
return parselength
|
||||
}
|
||||
|
||||
// DwarfEndian determines the endianness of the DWARF by using the version number field in the debug_info section
|
||||
// Trick borrowed from "debug/dwarf".New()
|
||||
func DwarfEndian(infoSec []byte) binary.ByteOrder {
|
||||
if len(infoSec) < 6 {
|
||||
return binary.BigEndian
|
||||
}
|
||||
x, y := infoSec[4], infoSec[5]
|
||||
switch {
|
||||
case x == 0 && y == 0:
|
||||
return binary.BigEndian
|
||||
case x == 0:
|
||||
return binary.BigEndian
|
||||
case y == 0:
|
||||
return binary.LittleEndian
|
||||
default:
|
||||
return binary.BigEndian
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package frame_test
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
@ -24,6 +25,6 @@ func BenchmarkParse(b *testing.B) {
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
frame.Parse(data)
|
||||
frame.Parse(data, binary.BigEndian)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ type DWRule struct {
|
||||
|
||||
type FrameContext struct {
|
||||
loc uint64
|
||||
order binary.ByteOrder
|
||||
address uint64
|
||||
cfa CurrentFrameAddress
|
||||
regs map[uint64]DWRule
|
||||
@ -138,6 +139,7 @@ func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
|
||||
// Unwind the stack to find the return address register.
|
||||
func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameContext {
|
||||
frame := executeCIEInstructions(fde.CIE)
|
||||
frame.order = fde.order
|
||||
frame.loc = fde.Begin()
|
||||
frame.address = pc
|
||||
fdeInstructions := make([]byte, len(fde.Instructions))
|
||||
@ -237,14 +239,14 @@ func advanceloc1(frame *FrameContext) {
|
||||
|
||||
func advanceloc2(frame *FrameContext) {
|
||||
var delta uint16
|
||||
binary.Read(frame.buf, binary.BigEndian, &delta)
|
||||
binary.Read(frame.buf, frame.order, &delta)
|
||||
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
|
||||
func advanceloc4(frame *FrameContext) {
|
||||
var delta uint32
|
||||
binary.Read(frame.buf, binary.BigEndian, &delta)
|
||||
binary.Read(frame.buf, frame.order, &delta)
|
||||
|
||||
frame.loc += uint64(delta) * frame.codeAlignment
|
||||
}
|
||||
@ -280,7 +282,7 @@ func restore(frame *FrameContext) {
|
||||
|
||||
func setloc(frame *FrameContext) {
|
||||
var loc uint64
|
||||
binary.Read(frame.buf, binary.BigEndian, &loc)
|
||||
binary.Read(frame.buf, frame.order, &loc)
|
||||
|
||||
frame.loc = loc
|
||||
}
|
||||
|
||||
@ -193,13 +193,21 @@ func (dbp *Process) addThread(port int, attach bool) (*Thread, error) {
|
||||
func (dbp *Process) parseDebugFrame(exe *macho.File, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
if sec := exe.Section("__debug_frame"); sec != nil {
|
||||
debugFrameSec := exe.Section("__debug_frame")
|
||||
debugInfoSec := exe.Section("__debug_info")
|
||||
|
||||
if debugFrameSec != nil && debugInfoSec != nil {
|
||||
debugFrame, err := exe.Section("__debug_frame").Data()
|
||||
if err != nil {
|
||||
fmt.Println("could not get __debug_frame section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame)
|
||||
dat, err := debugInfoSec.Data()
|
||||
if err != nil {
|
||||
fmt.Println("could not get .debug_info section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat))
|
||||
} else {
|
||||
fmt.Println("could not find __debug_frame section in binary")
|
||||
os.Exit(1)
|
||||
|
||||
@ -179,13 +179,21 @@ func (dbp *Process) findExecutable(path string) (*elf.File, error) {
|
||||
func (dbp *Process) parseDebugFrame(exe *elf.File, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
if sec := exe.Section(".debug_frame"); sec != nil {
|
||||
debugFrameSec := exe.Section(".debug_frame")
|
||||
debugInfoSec := exe.Section(".debug_info")
|
||||
|
||||
if debugFrameSec != nil && debugInfoSec != nil {
|
||||
debugFrame, err := exe.Section(".debug_frame").Data()
|
||||
if err != nil {
|
||||
fmt.Println("could not get .debug_frame section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame)
|
||||
dat, err := debugInfoSec.Data()
|
||||
if err != nil {
|
||||
fmt.Println("could not get .debug_info section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat))
|
||||
} else {
|
||||
fmt.Println("could not find .debug_frame section in binary")
|
||||
os.Exit(1)
|
||||
|
||||
@ -158,16 +158,24 @@ func (dbp *Process) addThread(hThread sys.Handle, threadID int, attach bool) (*T
|
||||
func (dbp *Process) parseDebugFrame(exe *pe.File, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
if sec := exe.Section(".debug_frame"); sec != nil {
|
||||
debugFrame, err := sec.Data()
|
||||
if err != nil && uint32(len(debugFrame)) < sec.Size {
|
||||
debugFrameSec := exe.Section(".debug_frame")
|
||||
debugInfoSec := exe.Section(".debug_info")
|
||||
|
||||
if debugFrameSec != nil && debugInfoSec != nil {
|
||||
debugFrame, err := debugFrameSec.Data()
|
||||
if err != nil && uint32(len(debugFrame)) < debugFrameSec.Size {
|
||||
fmt.Println("could not get .debug_frame section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if 0 < sec.VirtualSize && sec.VirtualSize < sec.Size {
|
||||
debugFrame = debugFrame[:sec.VirtualSize]
|
||||
if 0 < debugFrameSec.VirtualSize && debugFrameSec.VirtualSize < debugFrameSec.Size {
|
||||
debugFrame = debugFrame[:debugFrameSec.VirtualSize]
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame)
|
||||
dat, err := debugInfoSec.Data()
|
||||
if err != nil {
|
||||
fmt.Println("could not get .debug_info section", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
dbp.frameEntries = frame.Parse(debugFrame, frame.DwarfEndian(dat))
|
||||
} else {
|
||||
fmt.Println("could not find .debug_frame section in binary")
|
||||
os.Exit(1)
|
||||
|
||||
Reference in New Issue
Block a user