debugger.go 10.3 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 94 95 96 97
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)
	}
	d.process = p
	return nil
}

D
Dan Mace 已提交
98
func (d *Debugger) State() (*api.DebuggerState, error) {
99 100 101 102 103 104 105 106
	var (
		state  *api.DebuggerState
		thread *api.Thread
	)
	th := d.process.CurrentThread
	if th != nil {
		thread = api.ConvertThread(th)
	}
D
Dan Mace 已提交
107

108 109 110 111 112
	var breakpoint *api.Breakpoint
	bp := d.process.CurrentBreakpoint()
	if bp != nil {
		breakpoint = api.ConvertBreakpoint(bp)
	}
D
Dan Mace 已提交
113

114 115 116 117 118
	state = &api.DebuggerState{
		Breakpoint:    breakpoint,
		CurrentThread: thread,
		Exited:        d.process.Exited(),
	}
D
Dan Mace 已提交
119

120
	return state, nil
D
Dan Mace 已提交
121 122
}

D
Derek Parker 已提交
123 124
func (d *Debugger) CreateBreakpoint(requestedBp *api.Breakpoint) (*api.Breakpoint, error) {
	var createdBp *api.Breakpoint
125 126 127 128 129 130 131 132 133
	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 已提交
134

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

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

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

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

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

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

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

D
Derek Parker 已提交
265 266
	if len(bp.Variables) > 0 {
		bpi.Variables = make([]api.Variable, len(bp.Variables))
A
aarzilli 已提交
267
	}
D
Derek Parker 已提交
268 269
	for i := range bp.Variables {
		v, err := d.process.CurrentThread.EvalVariable(bp.Variables[i])
A
aarzilli 已提交
270 271 272 273 274 275 276 277 278
		if err != nil {
			return err
		}
		bpi.Variables[i] = api.ConvertVar(v)
	}

	return nil
}

D
Dan Mace 已提交
279 280 281 282 283 284 285
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{}
286 287 288
	for f := range d.process.Sources() {
		if regex.Match([]byte(f)) {
			files = append(files, f)
D
Dan Mace 已提交
289
		}
290
	}
D
Dan Mace 已提交
291 292 293 294 295 296 297 298 299 300
	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{}
301 302 303
	for _, f := range d.process.Funcs() {
		if f.Sym != nil && regex.Match([]byte(f.Name)) {
			funcs = append(funcs, f.Name)
D
Dan Mace 已提交
304
		}
305
	}
D
Dan Mace 已提交
306 307 308 309 310 311 312 313 314 315
	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{}
316 317 318 319 320 321 322 323 324 325 326
	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 已提交
327
		}
328
	}
D
Dan Mace 已提交
329 330 331
	return vars, err
}

332 333 334 335 336 337 338 339 340 341 342 343
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
}

344 345
func (d *Debugger) LocalVariables(threadID int) ([]api.Variable, error) {
	vars := []api.Variable{}
346 347 348 349 350 351 352 353 354 355 356
	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))
	}
357 358 359 360 361
	return vars, err
}

func (d *Debugger) FunctionArguments(threadID int) ([]api.Variable, error) {
	vars := []api.Variable{}
362 363 364
	thread, found := d.process.Threads[threadID]
	if !found {
		return nil, fmt.Errorf("couldn't find thread %d", threadID)
D
Dan Mace 已提交
365
	}
366 367 368
	pv, err := thread.FunctionArguments()
	if err != nil {
		return nil, err
D
Dan Mace 已提交
369
	}
370 371
	for _, v := range pv {
		vars = append(vars, api.ConvertVar(v))
D
Dan Mace 已提交
372
	}
373
	return vars, err
D
Dan Mace 已提交
374 375
}

376 377 378 379 380 381 382 383
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 已提交
384
	}
385 386
	converted := api.ConvertVar(v)
	return &converted, err
D
Dan Mace 已提交
387 388
}

389 390 391 392 393
func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
	goroutines := []*api.Goroutine{}
	gs, err := d.process.GoroutinesInfo()
	if err != nil {
		return nil, err
D
Dan Mace 已提交
394
	}
395 396
	for _, g := range gs {
		goroutines = append(goroutines, api.ConvertGoroutine(g))
D
Dan Mace 已提交
397
	}
398
	return goroutines, err
D
Dan Mace 已提交
399
}
A
aarzilli 已提交
400 401 402 403 404 405

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

	if goroutineId < 0 {
D
Derek Parker 已提交
406
		rawlocs, err = d.process.CurrentThread.Stacktrace(depth)
A
aarzilli 已提交
407 408 409 410 411 412 413 414 415 416
		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 已提交
417
				rawlocs, err = d.process.GoroutineStacktrace(g, depth)
A
aarzilli 已提交
418 419 420 421 422 423 424 425 426 427 428 429
				if err != nil {
					return nil, err
				}
				break
			}
		}

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

D
Derek Parker 已提交
430
	return convertStacktrace(rawlocs), nil
A
aarzilli 已提交
431 432
}

D
Derek Parker 已提交
433 434
func convertStacktrace(rawlocs []proc.Location) []api.Location {
	locations := make([]api.Location, 0, len(rawlocs))
A
aarzilli 已提交
435 436 437 438 439
	for i := range rawlocs {
		rawlocs[i].Line--
		locations = append(locations, api.ConvertLocation(rawlocs[i]))
	}

A
aarzilli 已提交
440
	return locations
A
aarzilli 已提交
441
}