debugger.go 12.5 KB
Newer Older
D
Dan Mace 已提交
1 2 3
package debugger

import (
4
	"debug/gosym"
5
	"errors"
D
Dan Mace 已提交
6 7 8 9
	"fmt"
	"log"
	"regexp"

D
Derek Parker 已提交
10
	"github.com/derekparker/delve/proc"
D
Dan Mace 已提交
11
	"github.com/derekparker/delve/service/api"
D
Derek Parker 已提交
12
	sys "golang.org/x/sys/unix"
D
Dan Mace 已提交
13 14
)

D
Derek Parker 已提交
15 16 17
// Debugger service.
//
// Debugger provides a higher level of
D
Derek Parker 已提交
18
// abstraction over proc.Process.
D
Derek Parker 已提交
19 20 21 22
// It handles converting from internal types to
// the types expected by clients. It also handles
// functionality needed by clients, but not needed in
// lower lever packages such as proc.
D
Dan Mace 已提交
23
type Debugger struct {
24
	config  *Config
D
Derek Parker 已提交
25
	process *proc.Process
D
Dan Mace 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
}

// Config provides the configuration to start a Debugger.
//
// Only one of ProcessArgs or AttachPid should be specified. If ProcessArgs is
// provided, a new process will be launched. Otherwise, the debugger will try
// to attach to an existing process with AttachPid.
type Config struct {
	// ProcessArgs are the arguments to launch a new process.
	ProcessArgs []string
	// AttachPid is the PID of an existing process to which the debugger should
	// attach.
	AttachPid int
}

// New creates a new Debugger.
42 43 44
func New(config *Config) (*Debugger, error) {
	d := &Debugger{
		config: config,
D
Dan Mace 已提交
45 46 47 48 49
	}

	// Create the process by either attaching or launching.
	if d.config.AttachPid > 0 {
		log.Printf("attaching to pid %d", d.config.AttachPid)
D
Derek Parker 已提交
50
		p, err := proc.Attach(d.config.AttachPid)
D
Dan Mace 已提交
51
		if err != nil {
52
			return nil, attachErrorMessage(d.config.AttachPid, err)
D
Dan Mace 已提交
53 54 55 56
		}
		d.process = p
	} else {
		log.Printf("launching process with args: %v", d.config.ProcessArgs)
D
Derek Parker 已提交
57
		p, err := proc.Launch(d.config.ProcessArgs)
D
Dan Mace 已提交
58
		if err != nil {
59
			return nil, fmt.Errorf("could not launch process: %s", err)
D
Dan Mace 已提交
60 61 62
		}
		d.process = p
	}
63
	return d, nil
D
Dan Mace 已提交
64 65
}

D
Derek Parker 已提交
66 67 68 69
func (d *Debugger) ProcessPid() int {
	return d.process.Pid
}

D
Dan Mace 已提交
70
func (d *Debugger) Detach(kill bool) error {
71 72 73 74 75
	if d.config.AttachPid != 0 {
		return d.process.Detach(kill)
	} else {
		return d.process.Kill()
	}
D
Dan Mace 已提交
76 77
}

D
Derek Parker 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
func (d *Debugger) Restart() error {
	if !d.process.Exited() {
		if d.process.Running() {
			d.process.Halt()
		}
		// Ensure the process is in a PTRACE_STOP.
		if err := sys.Kill(d.ProcessPid(), sys.SIGSTOP); err != nil {
			return err
		}
		if err := d.Detach(true); err != nil {
			return err
		}
	}
	p, err := proc.Launch(d.config.ProcessArgs)
	if err != nil {
		return fmt.Errorf("could not launch process: %s", err)
	}
95 96 97 98
	for addr, bp := range d.process.Breakpoints {
		if bp.Temp {
			continue
		}
99 100 101 102
		if _, err := p.SetBreakpoint(addr); err != nil {
			return err
		}
	}
D
Derek Parker 已提交
103 104 105 106
	d.process = p
	return nil
}

D
Dan Mace 已提交
107
func (d *Debugger) State() (*api.DebuggerState, error) {
108 109 110 111
	if d.process.Exited() {
		return nil, proc.ProcessExitedError{Pid: d.ProcessPid()}
	}

112
	var (
113 114 115
		state     *api.DebuggerState
		thread    *api.Thread
		goroutine *api.Goroutine
116
	)
117 118 119 120 121 122 123

	if d.process.CurrentThread != nil {
		thread = api.ConvertThread(d.process.CurrentThread)
	}

	if d.process.SelectedGoroutine != nil {
		goroutine = api.ConvertGoroutine(d.process.SelectedGoroutine)
124
	}
D
Dan Mace 已提交
125

126 127 128 129 130
	var breakpoint *api.Breakpoint
	bp := d.process.CurrentBreakpoint()
	if bp != nil {
		breakpoint = api.ConvertBreakpoint(bp)
	}
D
Dan Mace 已提交
131

132
	state = &api.DebuggerState{
133 134 135 136
		Breakpoint:        breakpoint,
		CurrentThread:     thread,
		SelectedGoroutine: goroutine,
		Exited:            d.process.Exited(),
137
	}
D
Dan Mace 已提交
138

139
	return state, nil
D
Dan Mace 已提交
140 141
}

D
Derek Parker 已提交
142
func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
143 144 145 146 147
	var (
		createdBp *api.Breakpoint
		addr      uint64
		err       error
	)
148 149
	switch {
	case len(requestedBp.File) > 0:
150
		addr, err = d.process.FindFileLocation(requestedBp.File, requestedBp.Line)
151
	case len(requestedBp.FunctionName) > 0:
152 153 154 155 156
		if requestedBp.Line >= 0 {
			addr, err = d.process.FindFunctionLocation(requestedBp.FunctionName, false, requestedBp.Line)
		} else {
			addr, err = d.process.FindFunctionLocation(requestedBp.FunctionName, true, 0)
		}
157
	default:
158 159 160 161 162
		addr = requestedBp.Addr
	}

	if err != nil {
		return nil, err
163
	}
D
Dan Mace 已提交
164

165
	bp, err := d.process.SetBreakpoint(addr)
166 167 168
	if err != nil {
		return nil, err
	}
A
aarzilli 已提交
169 170 171
	bp.Tracepoint = requestedBp.Tracepoint
	bp.Goroutine = requestedBp.Goroutine
	bp.Stacktrace = requestedBp.Stacktrace
D
Derek Parker 已提交
172
	bp.Variables = requestedBp.Variables
173 174 175
	createdBp = api.ConvertBreakpoint(bp)
	log.Printf("created breakpoint: %#v", createdBp)
	return createdBp, nil
D
Dan Mace 已提交
176 177
}

D
Derek Parker 已提交
178 179
func (d *Debugger) ClearBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
	var clearedBp *api.Breakpoint
180
	bp, err := d.process.ClearBreakpoint(requestedBp.Addr)
181 182 183 184 185
	if err != nil {
		return nil, fmt.Errorf("Can't clear breakpoint @%x: %s", requestedBp.Addr, err)
	}
	clearedBp = api.ConvertBreakpoint(bp)
	log.Printf("cleared breakpoint: %#v", clearedBp)
D
Dan Mace 已提交
186 187 188
	return clearedBp, err
}

D
Derek Parker 已提交
189 190
func (d *Debugger) Breakpoints() []*api.Breakpoint {
	bps := []*api.Breakpoint{}
191 192 193
	for _, bp := range d.process.Breakpoints {
		if bp.Temp {
			continue
D
Dan Mace 已提交
194
		}
195 196
		bps = append(bps, api.ConvertBreakpoint(bp))
	}
D
Dan Mace 已提交
197 198 199
	return bps
}

D
Derek Parker 已提交
200 201
func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint {
	for _, bp := range d.Breakpoints() {
D
Dan Mace 已提交
202 203 204 205 206 207 208 209 210
		if bp.ID == id {
			return bp
		}
	}
	return nil
}

func (d *Debugger) Threads() []*api.Thread {
	threads := []*api.Thread{}
211 212 213
	for _, th := range d.process.Threads {
		threads = append(threads, api.ConvertThread(th))
	}
D
Dan Mace 已提交
214 215 216 217 218 219 220 221 222 223 224 225
	return threads
}

func (d *Debugger) FindThread(id int) *api.Thread {
	for _, thread := range d.Threads() {
		if thread.ID == id {
			return thread
		}
	}
	return nil
}

D
Derek Parker 已提交
226
// Command handles commands which control the debugger lifecycle
D
Dan Mace 已提交
227 228 229 230
func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, error) {
	var err error
	switch command.Name {
	case api.Continue:
231 232
		log.Print("continuing")
		err = d.process.Continue()
A
aarzilli 已提交
233
		if err != nil {
234
			if exitedErr, exited := err.(proc.ProcessExitedError); exited {
235
				state := &api.DebuggerState{}
236 237 238 239
				state.Exited = true
				state.ExitStatus = exitedErr.Status
				state.Err = errors.New(exitedErr.Error())
				return state, nil
A
aarzilli 已提交
240 241 242
			}
			return nil, err
		}
243 244 245 246
		state, stateErr := d.State()
		if stateErr != nil {
			return state, stateErr
		}
A
aarzilli 已提交
247 248 249
		err = d.collectBreakpointInformation(state)
		return state, err

D
Dan Mace 已提交
250
	case api.Next:
251 252
		log.Print("nexting")
		err = d.process.Next()
D
Dan Mace 已提交
253
	case api.Step:
254 255
		log.Print("stepping")
		err = d.process.Step()
D
Dan Mace 已提交
256
	case api.SwitchThread:
257 258
		log.Printf("switching to thread %d", command.ThreadID)
		err = d.process.SwitchThread(command.ThreadID)
259 260 261
	case api.SwitchGoroutine:
		log.Printf("switching to goroutine %d", command.GoroutineID)
		err = d.process.SwitchGoroutine(command.GoroutineID)
D
Dan Mace 已提交
262 263 264 265 266 267 268
	case api.Halt:
		// RequestManualStop does not invoke any ptrace syscalls, so it's safe to
		// access the process directly.
		log.Print("halting")
		err = d.process.RequestManualStop()
	}
	if err != nil {
D
Derek Parker 已提交
269
		return nil, err
D
Dan Mace 已提交
270 271 272 273
	}
	return d.State()
}

A
aarzilli 已提交
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error {
	if state == nil || state.Breakpoint == nil {
		return nil
	}

	bp := state.Breakpoint
	bpi := &api.BreakpointInfo{}
	state.BreakpointInfo = bpi

	if bp.Goroutine {
		g, err := d.process.CurrentThread.GetG()
		if err != nil {
			return err
		}
		bpi.Goroutine = api.ConvertGoroutine(g)
	}

	if bp.Stacktrace > 0 {
D
Derek Parker 已提交
292
		rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
A
aarzilli 已提交
293 294 295
		if err != nil {
			return err
		}
296 297 298 299
		bpi.Stacktrace, err = d.convertStacktrace(rawlocs, false)
		if err != nil {
			return err
		}
A
aarzilli 已提交
300 301
	}

302 303 304 305 306
	s, err := d.process.CurrentThread.Scope()
	if err != nil {
		return err
	}

D
Derek Parker 已提交
307 308
	if len(bp.Variables) > 0 {
		bpi.Variables = make([]api.Variable, len(bp.Variables))
A
aarzilli 已提交
309
	}
D
Derek Parker 已提交
310
	for i := range bp.Variables {
311
		v, err := s.EvalVariable(bp.Variables[i])
A
aarzilli 已提交
312 313 314 315 316
		if err != nil {
			return err
		}
		bpi.Variables[i] = api.ConvertVar(v)
	}
317
	vars, err := functionArguments(s)
D
Derek Parker 已提交
318 319 320
	if err == nil {
		bpi.Arguments = vars
	}
A
aarzilli 已提交
321 322 323
	return nil
}

D
Dan Mace 已提交
324 325 326 327 328 329 330
func (d *Debugger) Sources(filter string) ([]string, error) {
	regex, err := regexp.Compile(filter)
	if err != nil {
		return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
	}

	files := []string{}
331 332 333
	for f := range d.process.Sources() {
		if regex.Match([]byte(f)) {
			files = append(files, f)
D
Dan Mace 已提交
334
		}
335
	}
D
Dan Mace 已提交
336 337 338 339
	return files, nil
}

func (d *Debugger) Functions(filter string) ([]string, error) {
340 341 342 343
	return regexFilterFuncs(filter, d.process.Funcs())
}

func regexFilterFuncs(filter string, allFuncs []gosym.Func) ([]string, error) {
D
Dan Mace 已提交
344 345 346 347 348 349
	regex, err := regexp.Compile(filter)
	if err != nil {
		return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
	}

	funcs := []string{}
350
	for _, f := range allFuncs {
351 352
		if f.Sym != nil && regex.Match([]byte(f.Name)) {
			funcs = append(funcs, f.Name)
D
Dan Mace 已提交
353
		}
354
	}
D
Dan Mace 已提交
355 356 357 358 359 360 361 362 363 364
	return funcs, nil
}

func (d *Debugger) PackageVariables(threadID int, filter string) ([]api.Variable, error) {
	regex, err := regexp.Compile(filter)
	if err != nil {
		return nil, fmt.Errorf("invalid filter argument: %s", err.Error())
	}

	vars := []api.Variable{}
365 366 367 368
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
	}
369 370 371 372 373
	scope, err := thread.Scope()
	if err != nil {
		return nil, err
	}
	pv, err := scope.PackageVariables()
374 375 376 377 378 379
	if err != nil {
		return nil, err
	}
	for _, v := range pv {
		if regex.Match([]byte(v.Name)) {
			vars = append(vars, api.ConvertVar(v))
D
Dan Mace 已提交
380
		}
381
	}
D
Dan Mace 已提交
382 383 384
	return vars, err
}

385 386 387 388 389 390 391 392 393 394 395 396
func (d *Debugger) Registers(threadID int) (string, error) {
	thread, found := d.process.Threads[threadID]
	if !found {
		return "", fmt.Errorf("couldn't find thread %d", threadID)
	}
	regs, err := thread.Registers()
	if err != nil {
		return "", err
	}
	return regs.String(), err
}

397 398 399 400 401 402 403 404
func convertVars(pv []*proc.Variable) []api.Variable {
	vars := make([]api.Variable, 0, len(pv))
	for _, v := range pv {
		vars = append(vars, api.ConvertVar(v))
	}
	return vars
}

405 406 407 408
func (d *Debugger) LocalVariables(scope api.EvalScope) ([]api.Variable, error) {
	s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame)
	if err != nil {
		return nil, err
409
	}
410
	pv, err := s.LocalVariables()
411 412 413
	if err != nil {
		return nil, err
	}
414
	return convertVars(pv), err
415 416
}

417 418 419 420
func (d *Debugger) FunctionArguments(scope api.EvalScope) ([]api.Variable, error) {
	s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame)
	if err != nil {
		return nil, err
D
Dan Mace 已提交
421
	}
422 423 424 425 426
	return functionArguments(s)
}

func functionArguments(s *proc.EvalScope) ([]api.Variable, error) {
	pv, err := s.FunctionArguments()
427 428
	if err != nil {
		return nil, err
D
Dan Mace 已提交
429
	}
430
	vars := make([]api.Variable, 0, len(pv))
431 432
	for _, v := range pv {
		vars = append(vars, api.ConvertVar(v))
D
Dan Mace 已提交
433
	}
D
Derek Parker 已提交
434
	return vars, nil
D
Dan Mace 已提交
435 436
}

437 438 439 440
func (d *Debugger) EvalVariableInScope(scope api.EvalScope, symbol string) (*api.Variable, error) {
	s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame)
	if err != nil {
		return nil, err
441
	}
442
	v, err := s.EvalVariable(symbol)
443 444
	if err != nil {
		return nil, err
D
Dan Mace 已提交
445
	}
446 447
	converted := api.ConvertVar(v)
	return &converted, err
D
Dan Mace 已提交
448 449
}

450 451 452 453 454 455 456 457
func (d *Debugger) SetVariableInScope(scope api.EvalScope, symbol, value string) error {
	s, err := d.process.ConvertEvalScope(scope.GoroutineID, scope.Frame)
	if err != nil {
		return err
	}
	return s.SetVariable(symbol, value)
}

458 459 460 461 462
func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
	goroutines := []*api.Goroutine{}
	gs, err := d.process.GoroutinesInfo()
	if err != nil {
		return nil, err
D
Dan Mace 已提交
463
	}
464 465
	for _, g := range gs {
		goroutines = append(goroutines, api.ConvertGoroutine(g))
D
Dan Mace 已提交
466
	}
467
	return goroutines, err
D
Dan Mace 已提交
468
}
A
aarzilli 已提交
469

470
func (d *Debugger) Stacktrace(goroutineId, depth int, full bool) ([]api.Stackframe, error) {
471
	var rawlocs []proc.Stackframe
A
aarzilli 已提交
472

A
aarzilli 已提交
473 474 475 476
	g, err := d.process.FindGoroutine(goroutineId)
	if err != nil {
		return nil, err
	}
A
aarzilli 已提交
477

A
aarzilli 已提交
478 479 480 481 482 483 484
	if g == nil {
		rawlocs, err = d.process.CurrentThread.Stacktrace(depth)
	} else {
		rawlocs, err = d.process.GoroutineStacktrace(g, depth)
	}
	if err != nil {
		return nil, err
A
aarzilli 已提交
485 486
	}

487
	return d.convertStacktrace(rawlocs, full)
A
aarzilli 已提交
488 489
}

490 491
func (d *Debugger) convertStacktrace(rawlocs []proc.Stackframe, full bool) ([]api.Stackframe, error) {
	locations := make([]api.Stackframe, 0, len(rawlocs))
A
aarzilli 已提交
492
	for i := range rawlocs {
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
		frame := api.Stackframe{Location: api.ConvertLocation(rawlocs[i].Call)}
		if full {
			scope := rawlocs[i].Scope(d.process.CurrentThread)
			lv, err := scope.LocalVariables()
			if err != nil {
				return nil, err
			}
			av, err := scope.FunctionArguments()
			if err != nil {
				return nil, err
			}
			frame.Locals = convertVars(lv)
			frame.Arguments = convertVars(av)
		}
		locations = append(locations, frame)
A
aarzilli 已提交
508 509
	}

510
	return locations, nil
A
aarzilli 已提交
511
}
512

513
func (d *Debugger) FindLocation(scope api.EvalScope, locStr string) ([]api.Location, error) {
514 515 516 517 518
	loc, err := parseLocationSpec(locStr)
	if err != nil {
		return nil, err
	}

519
	pc, err := d.process.PC()
520 521 522 523
	if err != nil {
		return nil, err
	}

524
	locs, err := loc.Find(d, pc, locStr)
525 526 527 528 529 530 531 532
	for i := range locs {
		file, line, fn := d.process.PCToLine(locs[i].PC)
		locs[i].File = file
		locs[i].Line = line
		locs[i].Function = api.ConvertFunction(fn)
	}
	return locs, err
}