提交 7d0d2cb3 编写于 作者: A aarzilli 提交者: Derek Parker

pkg/core: make code in core.go OS/arch agnostic

Make code in core.go OS and architecture agnostic in preparation for
adding Windows minidump support.
上级 73d636f7
......@@ -8,7 +8,6 @@ import (
"sync"
"github.com/derekparker/delve/pkg/proc"
"github.com/derekparker/delve/pkg/proc/linutil"
)
// A SplicedMemory represents a memory space formed from multiple regions,
......@@ -145,8 +144,13 @@ func (r *OffsetReaderAt) ReadMemory(buf []byte, addr uintptr) (n int, err error)
// Process represents a core file.
type Process struct {
mem proc.MemoryReader
Threads map[int]*Thread
pid int
entryPoint uint64
bi *proc.BinaryInfo
core *Core
breakpoints proc.BreakpointMap
currentThread *Thread
selectedGoroutine *proc.G
......@@ -155,12 +159,16 @@ type Process struct {
// Thread represents a thread in the core file being debugged.
type Thread struct {
regs linutil.AMD64Registers
th *LinuxPrStatus
th osThread
p *Process
common proc.CommonThread
}
type osThread interface {
registers(floatingPoint bool) (proc.Registers, error)
pid() int
}
var (
// ErrWriteCore is returned when attempting to write to the core
// process memory.
......@@ -178,21 +186,13 @@ var (
// OpenCore will open the core file and return a Process struct.
func OpenCore(corePath, exePath string) (*Process, error) {
core, err := readCore(corePath, exePath)
p, err := readLinuxAMD64Core(corePath, exePath)
if err != nil {
return nil, err
}
p := &Process{
core: core,
breakpoints: proc.NewBreakpointMap(),
bi: proc.NewBinaryInfo("linux", "amd64"),
}
for _, thread := range core.Threads {
thread.p = p
}
var wg sync.WaitGroup
err = p.bi.LoadBinaryInfo(exePath, core.entryPoint, &wg)
err = p.bi.LoadBinaryInfo(exePath, p.entryPoint, &wg)
wg.Wait()
if err == nil {
err = p.bi.LoadError()
......@@ -201,10 +201,6 @@ func OpenCore(corePath, exePath string) (*Process, error) {
return nil, err
}
for _, th := range p.core.Threads {
p.currentThread = th
break
}
p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
return p, nil
......@@ -240,7 +236,7 @@ func (p *Process) ClearCheckpoint(int) error { return errors.New("checkpoint not
// read memory into `data`, returning the length read, and returning an error if
// the length read is shorter than the length of the `data` buffer.
func (t *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
n, err = t.p.core.ReadMemory(data, addr)
n, err = t.p.mem.ReadMemory(data, addr)
if err == nil && n != len(data) {
err = ErrShortRead
}
......@@ -256,8 +252,13 @@ func (t *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
// Location returns the location of this thread based on
// the value of the instruction pointer register.
func (t *Thread) Location() (*proc.Location, error) {
f, l, fn := t.p.bi.PCToLine(t.th.Reg.Rip)
return &proc.Location{PC: t.th.Reg.Rip, File: f, Line: l, Fn: fn}, nil
regs, err := t.th.registers(false)
if err != nil {
return nil, err
}
pc := regs.PC()
f, l, fn := t.p.bi.PCToLine(pc)
return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
}
// Breakpoint returns the current breakpoint this thread is stopped at.
......@@ -269,17 +270,12 @@ func (t *Thread) Breakpoint() proc.BreakpointState {
// ThreadID returns the ID for this thread.
func (t *Thread) ThreadID() int {
return int(t.th.Pid)
return int(t.th.pid())
}
// Registers returns the current value of the registers for this thread.
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
var r linutil.AMD64Registers
r.Regs = t.regs.Regs
if floatingPoint {
r.Fpregs = t.regs.Fpregs
}
return &r, nil
return t.th.registers(floatingPoint)
}
// RestoreRegisters will only return an error for core files,
......@@ -408,7 +404,7 @@ func (p *Process) Common() *proc.CommonProcess {
// Pid returns the process ID of this process.
func (p *Process) Pid() int {
return p.core.Pid
return p.pid
}
// ResumeNotify is a no-op on core files as we cannot
......@@ -446,7 +442,7 @@ func (p *Process) SwitchGoroutine(gid int) error {
// SwitchThread will change the selected and active thread.
func (p *Process) SwitchThread(tid int) error {
if th, ok := p.core.Threads[tid]; ok {
if th, ok := p.Threads[tid]; ok {
p.currentThread = th
p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
return nil
......@@ -456,8 +452,8 @@ func (p *Process) SwitchThread(tid int) error {
// ThreadList will return a list of all threads currently in the process.
func (p *Process) ThreadList() []proc.Thread {
r := make([]proc.Thread, 0, len(p.core.Threads))
for _, v := range p.core.Threads {
r := make([]proc.Thread, 0, len(p.Threads))
for _, v := range p.Threads {
r = append(r, v)
}
return r
......@@ -465,6 +461,6 @@ func (p *Process) ThreadList() []proc.Thread {
// FindThread will return the thread with the corresponding thread ID.
func (p *Process) FindThread(threadID int) (proc.Thread, bool) {
t, ok := p.core.Threads[threadID]
t, ok := p.Threads[threadID]
return t, ok
}
......@@ -28,13 +28,13 @@ const NT_X86_XSTATE elf.NType = 0x202 // Note type for notes containing X86 XSAV
// NT_AUXV is the note type for notes containing a copy of the Auxv array
const NT_AUXV elf.NType = 0x6
// readCore reads a core file from corePath corresponding to the executable at
// readLinuxAMD64Core reads a core file from corePath corresponding to the executable at
// exePath. For details on the Linux ELF core format, see:
// http://www.gabriel.urdhr.fr/2015/05/29/core-file/,
// http://uhlo.blogspot.fr/2012/05/brief-look-into-core-dumps.html,
// elf_core_dump in http://lxr.free-electrons.com/source/fs/binfmt_elf.c,
// and, if absolutely desperate, readelf.c from the binutils source.
func readCore(corePath, exePath string) (*Core, error) {
func readLinuxAMD64Core(corePath, exePath string) (*Process, error) {
coreFile, err := elf.Open(corePath)
if err != nil {
return nil, err
......@@ -62,37 +62,51 @@ func readCore(corePath, exePath string) (*Core, error) {
memory := buildMemory(coreFile, exeELF, exe, notes)
entryPoint := findEntryPoint(notes)
core := &Core{
MemoryReader: memory,
Threads: map[int]*Thread{},
entryPoint: entryPoint,
p := &Process{
mem: memory,
Threads: map[int]*Thread{},
entryPoint: entryPoint,
bi: proc.NewBinaryInfo("linux", "amd64"),
breakpoints: proc.NewBreakpointMap(),
}
var lastThread *Thread
var lastThread *linuxAMD64Thread
for _, note := range notes {
switch note.Type {
case elf.NT_PRSTATUS:
t := note.Desc.(*LinuxPrStatus)
lastThread = &Thread{linutil.AMD64Registers{Regs: &t.Reg}, t, nil, proc.CommonThread{}}
core.Threads[int(t.Pid)] = lastThread
lastThread = &linuxAMD64Thread{linutil.AMD64Registers{Regs: &t.Reg}, t}
p.Threads[int(t.Pid)] = &Thread{lastThread, p, proc.CommonThread{}}
if p.currentThread == nil {
p.currentThread = p.Threads[int(t.Pid)]
}
case NT_X86_XSTATE:
if lastThread != nil {
lastThread.regs.Fpregs = note.Desc.(*linutil.AMD64Xstate).Decode()
}
case elf.NT_PRPSINFO:
core.Pid = int(note.Desc.(*LinuxPrPsInfo).Pid)
p.pid = int(note.Desc.(*LinuxPrPsInfo).Pid)
}
}
return core, nil
return p, nil
}
type linuxAMD64Thread struct {
regs linutil.AMD64Registers
t *LinuxPrStatus
}
// Core represents a core file.
type Core struct {
proc.MemoryReader
Threads map[int]*Thread
Pid int
func (t *linuxAMD64Thread) registers(floatingPoint bool) (proc.Registers, error) {
var r linutil.AMD64Registers
r.Regs = t.regs.Regs
if floatingPoint {
r.Fpregs = t.regs.Fpregs
}
return &r, nil
}
entryPoint uint64
func (t *linuxAMD64Thread) pid() int {
return int(t.t.Pid)
}
// Note is a note from the PT_NOTE prog.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册