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

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

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

D
Derek Parker 已提交
14 15 16
// Debugger service.
//
// Debugger provides a higher level of
D
Derek Parker 已提交
17
// abstraction over proc.Process.
D
Derek Parker 已提交
18 19 20 21
// 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 已提交
22
type Debugger struct {
23
	config  *Config
D
Derek Parker 已提交
24
	process *proc.Process
D
Dan Mace 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
}

// 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.
41 42 43
func New(config *Config) (*Debugger, error) {
	d := &Debugger{
		config: config,
D
Dan Mace 已提交
44 45 46 47 48
	}

	// 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 已提交
49
		p, err := proc.Attach(d.config.AttachPid)
D
Dan Mace 已提交
50
		if err != nil {
51
			return nil, attachErrorMessage(d.config.AttachPid, err)
D
Dan Mace 已提交
52 53 54 55
		}
		d.process = p
	} else {
		log.Printf("launching process with args: %v", d.config.ProcessArgs)
D
Derek Parker 已提交
56
		p, err := proc.Launch(d.config.ProcessArgs)
D
Dan Mace 已提交
57
		if err != nil {
58
			return nil, fmt.Errorf("could not launch process: %s", err)
D
Dan Mace 已提交
59 60 61
		}
		d.process = p
	}
62
	return d, nil
D
Dan Mace 已提交
63 64
}

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

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

D
Derek Parker 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
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)
	}
94 95 96 97 98
	for addr, _ := range d.process.Breakpoints {
		if _, err := p.SetBreakpoint(addr); err != nil {
			return err
		}
	}
D
Derek Parker 已提交
99 100 101 102
	d.process = p
	return nil
}

D
Dan Mace 已提交
103
func (d *Debugger) State() (*api.DebuggerState, error) {
104 105 106 107 108 109 110 111
	var (
		state  *api.DebuggerState
		thread *api.Thread
	)
	th := d.process.CurrentThread
	if th != nil {
		thread = api.ConvertThread(th)
	}
D
Dan Mace 已提交
112

113 114 115 116 117
	var breakpoint *api.Breakpoint
	bp := d.process.CurrentBreakpoint()
	if bp != nil {
		breakpoint = api.ConvertBreakpoint(bp)
	}
D
Dan Mace 已提交
118

119 120 121 122 123
	state = &api.DebuggerState{
		Breakpoint:    breakpoint,
		CurrentThread: thread,
		Exited:        d.process.Exited(),
	}
D
Dan Mace 已提交
124

125
	return state, nil
D
Dan Mace 已提交
126 127
}

D
Derek Parker 已提交
128 129
func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
	var createdBp *api.Breakpoint
130 131 132 133 134 135 136 137 138
	var loc string
	switch {
	case len(requestedBp.File) > 0:
		loc = fmt.Sprintf("%s:%d", requestedBp.File, requestedBp.Line)
	case len(requestedBp.FunctionName) > 0:
		loc = requestedBp.FunctionName
	default:
		return nil, fmt.Errorf("no file or function name specified")
	}
D
Dan Mace 已提交
139

140
	bp, err := d.process.SetBreakpointByLocation(loc)
141 142 143
	if err != nil {
		return nil, err
	}
A
aarzilli 已提交
144 145 146
	bp.Tracepoint = requestedBp.Tracepoint
	bp.Goroutine = requestedBp.Goroutine
	bp.Stacktrace = requestedBp.Stacktrace
D
Derek Parker 已提交
147
	bp.Variables = requestedBp.Variables
148 149 150
	createdBp = api.ConvertBreakpoint(bp)
	log.Printf("created breakpoint: %#v", createdBp)
	return createdBp, nil
D
Dan Mace 已提交
151 152
}

D
Derek Parker 已提交
153 154
func (d *Debugger) ClearBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
	var clearedBp *api.Breakpoint
155
	bp, err := d.process.ClearBreakpoint(requestedBp.Addr)
156 157 158 159 160
	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 已提交
161 162 163
	return clearedBp, err
}

D
Derek Parker 已提交
164 165
func (d *Debugger) Breakpoints() []*api.Breakpoint {
	bps := []*api.Breakpoint{}
166 167 168
	for _, bp := range d.process.Breakpoints {
		if bp.Temp {
			continue
D
Dan Mace 已提交
169
		}
170 171
		bps = append(bps, api.ConvertBreakpoint(bp))
	}
D
Dan Mace 已提交
172 173 174
	return bps
}

D
Derek Parker 已提交
175 176
func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint {
	for _, bp := range d.Breakpoints() {
D
Dan Mace 已提交
177 178 179 180 181 182 183 184 185
		if bp.ID == id {
			return bp
		}
	}
	return nil
}

func (d *Debugger) Threads() []*api.Thread {
	threads := []*api.Thread{}
186 187 188
	for _, th := range d.process.Threads {
		threads = append(threads, api.ConvertThread(th))
	}
D
Dan Mace 已提交
189 190 191 192 193 194 195 196 197 198 199 200
	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 已提交
201
// Command handles commands which control the debugger lifecycle
D
Dan Mace 已提交
202 203 204 205
func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, error) {
	var err error
	switch command.Name {
	case api.Continue:
206 207
		log.Print("continuing")
		err = d.process.Continue()
208 209 210 211
		state, stateErr := d.State()
		if stateErr != nil {
			return state, stateErr
		}
A
aarzilli 已提交
212
		if err != nil {
213
			if exitedErr, exited := err.(proc.ProcessExitedError); exited {
214 215 216 217
				state.Exited = true
				state.ExitStatus = exitedErr.Status
				state.Err = errors.New(exitedErr.Error())
				return state, nil
A
aarzilli 已提交
218 219 220 221 222 223
			}
			return nil, err
		}
		err = d.collectBreakpointInformation(state)
		return state, err

D
Dan Mace 已提交
224
	case api.Next:
225 226
		log.Print("nexting")
		err = d.process.Next()
D
Dan Mace 已提交
227
	case api.Step:
228 229
		log.Print("stepping")
		err = d.process.Step()
D
Dan Mace 已提交
230
	case api.SwitchThread:
231 232
		log.Printf("switching to thread %d", command.ThreadID)
		err = d.process.SwitchThread(command.ThreadID)
D
Dan Mace 已提交
233 234 235 236 237 238 239
	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 已提交
240
		return nil, err
D
Dan Mace 已提交
241 242 243 244
	}
	return d.State()
}

A
aarzilli 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
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 已提交
263
		rawlocs, err := d.process.CurrentThread.Stacktrace(bp.Stacktrace)
A
aarzilli 已提交
264 265 266
		if err != nil {
			return err
		}
D
Derek Parker 已提交
267
		bpi.Stacktrace = convertStacktrace(rawlocs)
A
aarzilli 已提交
268 269
	}

D
Derek Parker 已提交
270 271
	if len(bp.Variables) > 0 {
		bpi.Variables = make([]api.Variable, len(bp.Variables))
A
aarzilli 已提交
272
	}
D
Derek Parker 已提交
273 274
	for i := range bp.Variables {
		v, err := d.process.CurrentThread.EvalVariable(bp.Variables[i])
A
aarzilli 已提交
275 276 277 278 279
		if err != nil {
			return err
		}
		bpi.Variables[i] = api.ConvertVar(v)
	}
D
Derek Parker 已提交
280 281 282 283
	vars, err := d.FunctionArguments(d.process.CurrentThread.Id)
	if err == nil {
		bpi.Arguments = vars
	}
A
aarzilli 已提交
284 285 286 287

	return nil
}

D
Dan Mace 已提交
288 289 290 291 292 293 294
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{}
295 296 297
	for f := range d.process.Sources() {
		if regex.Match([]byte(f)) {
			files = append(files, f)
D
Dan Mace 已提交
298
		}
299
	}
D
Dan Mace 已提交
300 301 302 303 304 305 306 307 308 309
	return files, nil
}

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

	funcs := []string{}
310 311 312
	for _, f := range d.process.Funcs() {
		if f.Sym != nil && regex.Match([]byte(f.Name)) {
			funcs = append(funcs, f.Name)
D
Dan Mace 已提交
313
		}
314
	}
D
Dan Mace 已提交
315 316 317 318 319 320 321 322 323 324
	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{}
325 326 327 328 329 330 331 332 333 334 335
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
	}
	pv, err := thread.PackageVariables()
	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 已提交
336
		}
337
	}
D
Dan Mace 已提交
338 339 340
	return vars, err
}

341 342 343 344 345 346 347 348 349 350 351 352
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
}

353 354
func (d *Debugger) LocalVariables(threadID int) ([]api.Variable, error) {
	vars := []api.Variable{}
355 356 357 358 359 360 361 362 363 364 365
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
	}
	pv, err := thread.LocalVariables()
	if err != nil {
		return nil, err
	}
	for _, v := range pv {
		vars = append(vars, api.ConvertVar(v))
	}
366 367 368 369 370
	return vars, err
}

func (d *Debugger) FunctionArguments(threadID int) ([]api.Variable, error) {
	vars := []api.Variable{}
371 372 373
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
D
Dan Mace 已提交
374
	}
375 376 377
	pv, err := thread.FunctionArguments()
	if err != nil {
		return nil, err
D
Dan Mace 已提交
378
	}
379 380
	for _, v := range pv {
		vars = append(vars, api.ConvertVar(v))
D
Dan Mace 已提交
381
	}
D
Derek Parker 已提交
382
	return vars, nil
D
Dan Mace 已提交
383 384
}

385 386 387 388 389 390 391 392
func (d *Debugger) EvalVariableInThread(threadID int, symbol string) (*api.Variable, error) {
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
	}
	v, err := thread.EvalVariable(symbol)
	if err != nil {
		return nil, err
D
Dan Mace 已提交
393
	}
394 395
	converted := api.ConvertVar(v)
	return &converted, err
D
Dan Mace 已提交
396 397
}

398 399 400 401 402
func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
	goroutines := []*api.Goroutine{}
	gs, err := d.process.GoroutinesInfo()
	if err != nil {
		return nil, err
D
Dan Mace 已提交
403
	}
404 405
	for _, g := range gs {
		goroutines = append(goroutines, api.ConvertGoroutine(g))
D
Dan Mace 已提交
406
	}
407
	return goroutines, err
D
Dan Mace 已提交
408
}
A
aarzilli 已提交
409 410 411 412 413 414

func (d *Debugger) Stacktrace(goroutineId, depth int) ([]api.Location, error) {
	var rawlocs []proc.Location
	var err error

	if goroutineId < 0 {
D
Derek Parker 已提交
415
		rawlocs, err = d.process.CurrentThread.Stacktrace(depth)
A
aarzilli 已提交
416 417 418 419 420 421 422 423 424 425
		if err != nil {
			return nil, err
		}
	} else {
		gs, err := d.process.GoroutinesInfo()
		if err != nil {
			return nil, err
		}
		for _, g := range gs {
			if g.Id == goroutineId {
D
Derek Parker 已提交
426
				rawlocs, err = d.process.GoroutineStacktrace(g, depth)
A
aarzilli 已提交
427 428 429 430 431 432 433 434 435 436 437 438
				if err != nil {
					return nil, err
				}
				break
			}
		}

		if rawlocs == nil {
			return nil, fmt.Errorf("Unknown goroutine id %d\n", goroutineId)
		}
	}

D
Derek Parker 已提交
439
	return convertStacktrace(rawlocs), nil
A
aarzilli 已提交
440 441
}

D
Derek Parker 已提交
442 443
func convertStacktrace(rawlocs []proc.Location) []api.Location {
	locations := make([]api.Location, 0, len(rawlocs))
A
aarzilli 已提交
444 445 446 447 448
	for i := range rawlocs {
		rawlocs[i].Line--
		locations = append(locations, api.ConvertLocation(rawlocs[i]))
	}

A
aarzilli 已提交
449
	return locations
A
aarzilli 已提交
450
}