core.go 9.1 KB
Newer Older
1
package core
2 3

import (
4
	"errors"
5
	"fmt"
6
	"go/ast"
7
	"io"
8
	"sync"
9 10

	"github.com/derekparker/delve/pkg/proc"
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
)

// A SplicedMemory represents a memory space formed from multiple regions,
// each of which may override previously regions. For example, in the following
// core, the program text was loaded at 0x400000:
// Start               End                 Page Offset
// 0x0000000000400000  0x000000000044f000  0x0000000000000000
// but then it's partially overwritten with an RW mapping whose data is stored
// in the core file:
// Type           Offset             VirtAddr           PhysAddr
//                FileSiz            MemSiz              Flags  Align
// LOAD           0x0000000000004000 0x000000000049a000 0x0000000000000000
//                0x0000000000002000 0x0000000000002000  RW     1000
// This can be represented in a SplicedMemory by adding the original region,
// then putting the RW mapping on top of it.
type SplicedMemory struct {
	readers []readerEntry
}

type readerEntry struct {
	offset uintptr
	length uintptr
33
	reader proc.MemoryReader
34 35 36
}

// Add adds a new region to the SplicedMemory, which may override existing regions.
37
func (r *SplicedMemory) Add(reader proc.MemoryReader, off, length uintptr) {
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	if length == 0 {
		return
	}
	end := off + length - 1
	newReaders := make([]readerEntry, 0, len(r.readers))
	add := func(e readerEntry) {
		if e.length == 0 {
			return
		}
		newReaders = append(newReaders, e)
	}
	inserted := false
	// Walk through the list of regions, fixing up any that overlap and inserting the new one.
	for _, entry := range r.readers {
		entryEnd := entry.offset + entry.length - 1
		switch {
		case entryEnd < off:
			// Entry is completely before the new region.
			add(entry)
		case end < entry.offset:
			// Entry is completely after the new region.
			if !inserted {
				add(readerEntry{off, length, reader})
				inserted = true
			}
			add(entry)
		case off <= entry.offset && entryEnd <= end:
			// Entry is completely overwritten by the new region. Drop.
		case entry.offset < off && entryEnd <= end:
			// New region overwrites the end of the entry.
			entry.length = off - entry.offset
			add(entry)
		case off <= entry.offset && end < entryEnd:
			// New reader overwrites the beginning of the entry.
			if !inserted {
				add(readerEntry{off, length, reader})
				inserted = true
			}
			overlap := entry.offset - off
			entry.offset += overlap
			entry.length -= overlap
			add(entry)
		case entry.offset < off && end < entryEnd:
			// New region punches a hole in the entry. Split it in two and put the new region in the middle.
			add(readerEntry{entry.offset, off - entry.offset, entry.reader})
			add(readerEntry{off, length, reader})
			add(readerEntry{end + 1, entryEnd - end, entry.reader})
			inserted = true
		default:
			panic(fmt.Sprintf("Unhandled case: existing entry is %v len %v, new is %v len %v", entry.offset, entry.length, off, length))
		}
	}
	if !inserted {
		newReaders = append(newReaders, readerEntry{off, length, reader})
	}
	r.readers = newReaders
}

// ReadMemory implements MemoryReader.ReadMemory.
func (r *SplicedMemory) ReadMemory(buf []byte, addr uintptr) (n int, err error) {
	started := false
	for _, entry := range r.readers {
		if entry.offset+entry.length < addr {
			if !started {
				continue
			}
			return n, fmt.Errorf("hit unmapped area at %v after %v bytes", addr, n)
		}

		// Don't go past the region.
		pb := buf
		if addr+uintptr(len(buf)) > entry.offset+entry.length {
			pb = pb[:entry.offset+entry.length-addr]
		}
		pn, err := entry.reader.ReadMemory(pb, addr)
		n += pn
		if err != nil || pn != len(pb) {
			return n, err
		}
		buf = buf[pn:]
		addr += uintptr(pn)
		if len(buf) == 0 {
			// Done, don't bother scanning the rest.
			return n, nil
		}
	}
	if n == 0 {
		return 0, fmt.Errorf("offset %v did not match any regions", addr)
	}
	return n, nil
}

// OffsetReaderAt wraps a ReaderAt into a MemoryReader, subtracting a fixed
// offset from the address. This is useful to represent a mapping in an address
// space. For example, if program text is mapped in at 0x400000, an
// OffsetReaderAt with offset 0x400000 can be wrapped around file.Open(program)
// to return the results of a read in that part of the address space.
type OffsetReaderAt struct {
	reader io.ReaderAt
	offset uintptr
}

func (r *OffsetReaderAt) ReadMemory(buf []byte, addr uintptr) (n int, err error) {
	return r.reader.ReadAt(buf, int64(addr-r.offset))
}
143

144
type Process struct {
145
	bi                proc.BinaryInfo
146
	core              *Core
147
	breakpoints       map[uint64]*proc.Breakpoint
148
	currentThread     *LinuxPrStatus
149 150
	selectedGoroutine *proc.G
	allGCache         []*proc.G
151 152
}

153
type Thread struct {
154
	th *LinuxPrStatus
155
	p  *Process
156 157 158 159 160 161
}

var ErrWriteCore = errors.New("can not to core process")
var ErrShortRead = errors.New("short read")
var ErrContinueCore = errors.New("can not continue execution of core process")

162
func OpenCore(corePath, exePath string) (*Process, error) {
163 164 165 166
	core, err := readCore(corePath, exePath)
	if err != nil {
		return nil, err
	}
167
	p := &Process{
168
		core:        core,
169 170
		breakpoints: make(map[uint64]*proc.Breakpoint),
		bi:          proc.NewBinaryInfo("linux", "amd64"),
171 172 173 174 175 176 177 178 179 180 181
	}

	var wg sync.WaitGroup
	p.bi.LoadBinaryInfo(exePath, &wg)
	wg.Wait()

	for _, th := range p.core.Threads {
		p.currentThread = th
		break
	}

182
	ver, isextld, err := proc.GetGoInformation(p)
183 184 185 186
	if err != nil {
		return nil, err
	}

187 188
	p.bi.Arch.SetGStructOffset(ver, isextld)
	p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
189 190 191 192

	return p, nil
}

193
func (p *Process) BinInfo() *proc.BinaryInfo {
194 195 196
	return &p.bi
}

197 198 199 200 201 202 203 204
func (p *Process) Recorded() (bool, string)                { return true, "" }
func (p *Process) Restart(string) error                    { return ErrContinueCore }
func (p *Process) Direction(proc.Direction) error          { return ErrContinueCore }
func (p *Process) When() (string, error)                   { return "", nil }
func (p *Process) Checkpoint(string) (int, error)          { return -1, ErrContinueCore }
func (p *Process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil }
func (p *Process) ClearCheckpoint(int) error               { return errors.New("checkpoint not found") }

205
func (thread *Thread) ReadMemory(data []byte, addr uintptr) (n int, err error) {
206
	n, err = thread.p.core.ReadMemory(data, addr)
207 208 209
	if err == nil && n != len(data) {
		err = ErrShortRead
	}
210
	return n, err
211 212
}

213
func (thread *Thread) WriteMemory(addr uintptr, data []byte) (int, error) {
214 215 216
	return 0, ErrWriteCore
}

217
func (t *Thread) Location() (*proc.Location, error) {
218
	f, l, fn := t.p.bi.PCToLine(t.th.Reg.Rip)
219
	return &proc.Location{PC: t.th.Reg.Rip, File: f, Line: l, Fn: fn}, nil
220 221
}

222
func (t *Thread) Breakpoint() (*proc.Breakpoint, bool, error) {
223 224 225
	return nil, false, nil
}

226
func (t *Thread) ThreadID() int {
227 228 229
	return int(t.th.Pid)
}

230
func (t *Thread) Registers(floatingPoint bool) (proc.Registers, error) {
231 232 233 234
	//TODO(aarzilli): handle floating point registers
	return &t.th.Reg, nil
}

235
func (t *Thread) Arch() proc.Arch {
236
	return t.p.bi.Arch
237 238
}

239
func (t *Thread) BinInfo() *proc.BinaryInfo {
240 241 242
	return &t.p.bi
}

243
func (t *Thread) StepInstruction() error {
244 245 246
	return ErrContinueCore
}

247
func (t *Thread) Blocked() bool {
248 249 250
	return false
}

251 252 253 254
func (t *Thread) SetCurrentBreakpoint() error {
	return nil
}

255
func (p *Process) Breakpoints() map[uint64]*proc.Breakpoint {
256 257 258
	return p.breakpoints
}

259
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
260
	return nil, proc.NoBreakpointError{Addr: addr}
261 262
}

263
func (p *Process) ClearInternalBreakpoints() error {
264 265 266
	return nil
}

267
func (p *Process) ContinueOnce() (proc.Thread, error) {
268 269 270
	return nil, ErrContinueCore
}

271
func (p *Process) StepInstruction() error {
272 273 274
	return ErrContinueCore
}

275
func (p *Process) RequestManualStop() error {
276 277 278
	return nil
}

279 280
func (p *Process) CurrentThread() proc.Thread {
	return &Thread{p.currentThread, p}
281 282
}

283
func (p *Process) Detach(bool) error {
284 285 286
	return nil
}

287
func (p *Process) Exited() bool {
288 289 290
	return false
}

291
func (p *Process) AllGCache() *[]*proc.G {
292 293 294
	return &p.allGCache
}

295
func (p *Process) Halt() error {
296 297 298
	return nil
}

299
func (p *Process) Kill() error {
300 301 302
	return nil
}

303
func (p *Process) Pid() int {
304 305 306
	return p.core.Pid
}

307
func (p *Process) Running() bool {
308 309 310
	return false
}

311
func (p *Process) SelectedGoroutine() *proc.G {
312 313 314
	return p.selectedGoroutine
}

315
func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
316 317 318
	return nil, ErrWriteCore
}

319
func (p *Process) SwitchGoroutine(gid int) error {
320
	g, err := proc.FindGoroutine(p, gid)
321 322 323 324 325 326 327
	if err != nil {
		return err
	}
	if g == nil {
		// user specified -1 and selectedGoroutine is nil
		return nil
	}
328 329
	if g.Thread != nil {
		return p.SwitchThread(g.Thread.ThreadID())
330 331 332 333 334
	}
	p.selectedGoroutine = g
	return nil
}

335
func (p *Process) SwitchThread(tid int) error {
336 337
	if th, ok := p.core.Threads[tid]; ok {
		p.currentThread = th
338
		p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
339 340 341 342 343
		return nil
	}
	return fmt.Errorf("thread %d does not exist", tid)
}

344 345
func (p *Process) ThreadList() []proc.Thread {
	r := make([]proc.Thread, 0, len(p.core.Threads))
346
	for _, v := range p.core.Threads {
347
		r = append(r, &Thread{v, p})
348 349 350 351
	}
	return r
}

352
func (p *Process) FindThread(threadID int) (proc.Thread, bool) {
353
	t, ok := p.core.Threads[threadID]
354
	return &Thread{t, p}, ok
355
}