1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 // A FormatError indicates a failure to process information in or
19 // about a remote process, such as unexpected or missing information
20 // in the object file or runtime structures.
21 type FormatError
string
23 func (e FormatError
) String() string { return string(e
) }
25 // An UnknownArchitecture occurs when trying to load an object file
26 // that indicates an architecture not supported by the debugger.
27 type UnknownArchitecture elf
.Machine
29 func (e UnknownArchitecture
) String() string {
30 return "unknown architecture: " + elf
.Machine(e
).String()
33 // A ProcessNotStopped error occurs when attempting to read or write
34 // memory or registers of a process that is not stopped.
35 type ProcessNotStopped
struct{}
37 func (e ProcessNotStopped
) String() string { return "process not stopped" }
39 // An UnknownGoroutine error is an internal error representing an
40 // unrecognized G structure pointer.
41 type UnknownGoroutine
struct {
46 func (e UnknownGoroutine
) String() string {
47 return fmt
.Sprintf("internal error: unknown goroutine (G %#x)", e
.Goroutine
)
50 // A NoCurrentGoroutine error occurs when no goroutine is currently
51 // selected in a process (or when there are no goroutines in a
53 type NoCurrentGoroutine
struct{}
55 func (e NoCurrentGoroutine
) String() string { return "no current goroutine" }
57 // A Process represents a remote attached process.
62 // The symbol table of this process
65 // A possibly-stopped OS thread, or nil
66 threadCache proc
.Thread
68 // Types parsed from the remote process
69 types
map[proc
.Word
]*remoteType
71 // Types and values from the remote runtime package
74 // Runtime field indexes
77 // Globals from the sys package (or from no package)
79 lessstack
, goexit
, newproc
, deferproc
, newprocreadylocked
*gosym
.Func
90 breakpointHooks
map[proc
.Word
]*breakpointHook
91 goroutineCreateHook
*goroutineCreateHook
92 goroutineExitHook
*goroutineExitHook
94 // Current goroutine, or nil if there are no goroutines
95 curGoroutine
*Goroutine
97 // Goroutines by the address of their G structure
98 goroutines
map[proc
.Word
]*Goroutine
105 // NewProcess constructs a new remote process around a traced
106 // process, an architecture, and a symbol table.
107 func NewProcess(tproc proc
.Process
, arch Arch
, syms
*gosym
.Table
) (*Process
, os
.Error
) {
112 types
: make(map[proc
.Word
]*remoteType
),
113 breakpointHooks
: make(map[proc
.Word
]*breakpointHook
),
114 goroutineCreateHook
: new(goroutineCreateHook
),
115 goroutineExitHook
: new(goroutineExitHook
),
116 goroutines
: make(map[proc
.Word
]*Goroutine
),
119 // Fill in remote runtime
123 case p
.sys
.allg
.addr().base
== 0:
124 return nil, FormatError("failed to find runtime symbol 'allg'")
125 case p
.sys
.g0
.addr().base
== 0:
126 return nil, FormatError("failed to find runtime symbol 'g0'")
127 case p
.sys
.newprocreadylocked
== nil:
128 return nil, FormatError("failed to find runtime symbol 'newprocreadylocked'")
129 case p
.sys
.goexit
== nil:
130 return nil, FormatError("failed to find runtime symbol 'sys.goexit'")
133 // Get current goroutines
134 p
.goroutines
[p
.sys
.g0
.addr().base
] = &Goroutine
{p
.sys
.g0
, nil, false}
135 err
:= try(func(a aborter
) {
136 g
:= p
.sys
.allg
.aGet(a
)
138 gs
:= g
.(remoteStruct
)
139 fmt
.Printf("*** Found goroutine at %#x\n", gs
.addr().base
)
140 p
.goroutines
[gs
.addr().base
] = &Goroutine
{gs
, nil, false}
141 g
= gs
.field(p
.f
.G
.Alllink
).(remotePtr
).aGet(a
)
148 // Create internal breakpoints to catch new and exited goroutines
149 p
.OnBreakpoint(proc
.Word(p
.sys
.newprocreadylocked
.Entry
)).(*breakpointHook
).addHandler(readylockedBP
, true)
150 p
.OnBreakpoint(proc
.Word(p
.sys
.goexit
.Entry
)).(*breakpointHook
).addHandler(goexitBP
, true)
152 // Select current frames
153 for _
, g
:= range p
.goroutines
{
157 p
.selectSomeGoroutine()
162 func elfGoSyms(f
*elf
.File
) (*gosym
.Table
, os
.Error
) {
163 text
:= f
.Section(".text")
164 symtab
:= f
.Section(".gosymtab")
165 pclntab
:= f
.Section(".gopclntab")
166 if text
== nil || symtab
== nil || pclntab
== nil {
170 symdat
, err
:= symtab
.Data()
174 pclndat
, err
:= pclntab
.Data()
179 pcln
:= gosym
.NewLineTable(pclndat
, text
.Addr
)
180 tab
, err
:= gosym
.NewTable(symdat
, pcln
)
188 // NewProcessElf constructs a new remote process around a traced
189 // process and the process' ELF object.
190 func NewProcessElf(tproc proc
.Process
, f
*elf
.File
) (*Process
, os
.Error
) {
191 syms
, err
:= elfGoSyms(f
)
196 return nil, FormatError("Failed to find symbol table")
203 return nil, UnknownArchitecture(f
.Machine
)
205 return NewProcess(tproc
, arch
, syms
)
208 // bootstrap constructs the runtime structure of a remote process.
209 func (p
*Process
) bootstrap() {
210 // Manually construct runtime types
211 p
.runtime
.String
= newManualType(eval
.TypeOfNative(rt1String
{}), p
.Arch
)
212 p
.runtime
.Slice
= newManualType(eval
.TypeOfNative(rt1Slice
{}), p
.Arch
)
213 p
.runtime
.Eface
= newManualType(eval
.TypeOfNative(rt1Eface
{}), p
.Arch
)
215 p
.runtime
.Type
= newManualType(eval
.TypeOfNative(rt1Type
{}), p
.Arch
)
216 p
.runtime
.CommonType
= newManualType(eval
.TypeOfNative(rt1CommonType
{}), p
.Arch
)
217 p
.runtime
.UncommonType
= newManualType(eval
.TypeOfNative(rt1UncommonType
{}), p
.Arch
)
218 p
.runtime
.StructField
= newManualType(eval
.TypeOfNative(rt1StructField
{}), p
.Arch
)
219 p
.runtime
.StructType
= newManualType(eval
.TypeOfNative(rt1StructType
{}), p
.Arch
)
220 p
.runtime
.PtrType
= newManualType(eval
.TypeOfNative(rt1PtrType
{}), p
.Arch
)
221 p
.runtime
.ArrayType
= newManualType(eval
.TypeOfNative(rt1ArrayType
{}), p
.Arch
)
222 p
.runtime
.SliceType
= newManualType(eval
.TypeOfNative(rt1SliceType
{}), p
.Arch
)
224 p
.runtime
.Stktop
= newManualType(eval
.TypeOfNative(rt1Stktop
{}), p
.Arch
)
225 p
.runtime
.Gobuf
= newManualType(eval
.TypeOfNative(rt1Gobuf
{}), p
.Arch
)
226 p
.runtime
.G
= newManualType(eval
.TypeOfNative(rt1G
{}), p
.Arch
)
228 // Get addresses of type.*runtime.XType for discrimination.
229 rtv
:= reflect
.Indirect(reflect
.NewValue(&p
.runtime
)).(*reflect
.StructValue
)
230 rtvt
:= rtv
.Type().(*reflect
.StructType
)
231 for i
:= 0; i
< rtv
.NumField(); i
++ {
232 n
:= rtvt
.Field(i
).Name
233 if n
[0] != 'P' || n
[1] < 'A' || n
[1] > 'Z' {
236 sym
:= p
.syms
.LookupSym("type.*runtime." + n
[1:])
240 rtv
.Field(i
).(*reflect
.UintValue
).Set(sym
.Value
)
243 // Get runtime field indexes
244 fillRuntimeIndexes(&p
.runtime
, &p
.f
)
247 p
.runtime
.runtimeGStatus
= rt1GStatus
250 p
.sys
.lessstack
= p
.syms
.LookupFunc("sys.lessstack")
251 p
.sys
.goexit
= p
.syms
.LookupFunc("goexit")
252 p
.sys
.newproc
= p
.syms
.LookupFunc("sys.newproc")
253 p
.sys
.deferproc
= p
.syms
.LookupFunc("sys.deferproc")
254 p
.sys
.newprocreadylocked
= p
.syms
.LookupFunc("newprocreadylocked")
255 if allg
:= p
.syms
.LookupSym("allg"); allg
!= nil {
256 p
.sys
.allg
= remotePtr
{remote
{proc
.Word(allg
.Value
), p
}, p
.runtime
.G
}
258 if g0
:= p
.syms
.LookupSym("g0"); g0
!= nil {
259 p
.sys
.g0
= p
.runtime
.G
.mk(remote
{proc
.Word(g0
.Value
), p
}).(remoteStruct
)
263 func (p
*Process
) selectSomeGoroutine() {
264 // Once we have friendly goroutine ID's, there might be a more
265 // reasonable behavior for this.
267 for _
, g
:= range p
.goroutines
{
268 if !g
.isG0() && g
.frame
!= nil {
279 func (p
*Process
) someStoppedOSThread() proc
.Thread
{
280 if p
.threadCache
!= nil {
281 if _
, err
:= p
.threadCache
.Stopped(); err
== nil {
286 for _
, t
:= range p
.proc
.Threads() {
287 if _
, err
:= t
.Stopped(); err
== nil {
295 func (p
*Process
) Peek(addr proc
.Word
, out
[]byte) (int, os
.Error
) {
296 thr
:= p
.someStoppedOSThread()
298 return 0, ProcessNotStopped
{}
300 return thr
.Peek(addr
, out
)
303 func (p
*Process
) Poke(addr proc
.Word
, b
[]byte) (int, os
.Error
) {
304 thr
:= p
.someStoppedOSThread()
306 return 0, ProcessNotStopped
{}
308 return thr
.Poke(addr
, b
)
311 func (p
*Process
) peekUintptr(a aborter
, addr proc
.Word
) proc
.Word
{
312 return proc
.Word(mkUintptr(remote
{addr
, p
}).(remoteUint
).aGet(a
))
319 // OnBreakpoint returns the hook that is run when the program reaches
320 // the given program counter.
321 func (p
*Process
) OnBreakpoint(pc proc
.Word
) EventHook
{
322 if bp
, ok
:= p
.breakpointHooks
[pc
]; ok
{
325 // The breakpoint will register itself when a handler is added
326 return &breakpointHook
{commonHook
{nil, 0}, p
, pc
}
329 // OnGoroutineCreate returns the hook that is run when a goroutine is created.
330 func (p
*Process
) OnGoroutineCreate() EventHook
{
331 return p
.goroutineCreateHook
334 // OnGoroutineExit returns the hook that is run when a goroutine exits.
335 func (p
*Process
) OnGoroutineExit() EventHook
{ return p
.goroutineExitHook
}
337 // osThreadToGoroutine looks up the goroutine running on an OS thread.
338 func (p
*Process
) osThreadToGoroutine(t proc
.Thread
) (*Goroutine
, os
.Error
) {
339 regs
, err
:= t
.Regs()
344 gt
, ok
:= p
.goroutines
[g
]
346 return nil, UnknownGoroutine
{t
, g
}
351 // causesToEvents translates the stop causes of the underlying process
352 // into an event queue.
353 func (p
*Process
) causesToEvents() ([]Event
, os
.Error
) {
354 // Count causes we're interested in
356 for _
, t
:= range p
.proc
.Threads() {
357 if c
, err
:= t
.Stopped(); err
== nil {
358 switch c
:= c
.(type) {
359 case proc
.Breakpoint
:
368 // Translate causes to events
369 events
:= make([]Event
, nev
)
371 for _
, t
:= range p
.proc
.Threads() {
372 if c
, err
:= t
.Stopped(); err
== nil {
373 switch c
:= c
.(type) {
374 case proc
.Breakpoint
:
375 gt
, err
:= p
.osThreadToGoroutine(t
)
379 events
[i
] = &Breakpoint
{commonEvent
{p
, gt
}, t
, proc
.Word(c
)}
390 // postEvent appends an event to the posted queue. These events will
391 // be processed before any currently pending events.
392 func (p
*Process
) postEvent(ev Event
) {
393 p
.posted
= append(p
.posted
, ev
)
396 // processEvents processes events in the event queue until no events
397 // remain, a handler returns EAStop, or a handler returns an error.
398 // It returns either EAStop or EAContinue and possibly an error.
399 func (p
*Process
) processEvents() (EventAction
, os
.Error
) {
401 for len(p
.posted
) > 0 {
402 ev
, p
.posted
= p
.posted
[0], p
.posted
[1:]
403 action
, err
:= p
.processEvent(ev
)
404 if action
== EAStop
{
409 for len(p
.pending
) > 0 {
410 ev
, p
.pending
= p
.pending
[0], p
.pending
[1:]
411 action
, err
:= p
.processEvent(ev
)
412 if action
== EAStop
{
417 return EAContinue
, nil
420 // processEvent processes a single event, without manipulating the
421 // event queues. It returns either EAStop or EAContinue and possibly
423 func (p
*Process
) processEvent(ev Event
) (EventAction
, os
.Error
) {
426 var action EventAction
428 switch ev
:= p
.event
.(type) {
430 hook
, ok
:= p
.breakpointHooks
[ev
.pc
]
434 p
.curGoroutine
= ev
.Goroutine()
435 action
, err
= hook
.handle(ev
)
437 case *GoroutineCreate
:
438 p
.curGoroutine
= ev
.Goroutine()
439 action
, err
= p
.goroutineCreateHook
.handle(ev
)
442 action
, err
= p
.goroutineExitHook
.handle(ev
)
445 log
.Panicf("Unknown event type %T in queue", p
.event
)
450 } else if action
== EAStop
{
453 return EAContinue
, nil
456 // Event returns the last event that caused the process to stop. This
457 // may return nil if the process has never been stopped by an event.
459 // TODO(austin) Return nil if the user calls p.Stop()?
460 func (p
*Process
) Event() Event
{ return p
.event
}
466 // TODO(austin) Cont, WaitStop, and Stop. Need to figure out how
467 // event handling works with these. Originally I did it only in
468 // WaitStop, but if you Cont and there are pending events, then you
469 // have to not actually continue and wait until a WaitStop to process
470 // them, even if the event handlers will tell you to continue. We
471 // could handle them in both Cont and WaitStop to avoid this problem,
472 // but it's still weird if an event happens after the Cont and before
473 // the WaitStop that the handlers say to continue from. Or we could
474 // handle them on a separate thread. Then obviously you get weird
475 // asynchronous things, like prints while the user it typing a command,
476 // but that's not necessarily a bad thing.
478 // ContWait resumes process execution and waits for an event to occur
479 // that stops the process.
480 func (p
*Process
) ContWait() os
.Error
{
482 a
, err
:= p
.processEvents()
485 } else if a
== EAStop
{
488 err
= p
.proc
.Continue()
492 err
= p
.proc
.WaitStop()
496 for _
, g
:= range p
.goroutines
{
499 p
.pending
, err
= p
.causesToEvents()
507 // Out selects the caller frame of the current frame.
508 func (p
*Process
) Out() os
.Error
{
509 if p
.curGoroutine
== nil {
510 return NoCurrentGoroutine
{}
512 return p
.curGoroutine
.Out()
515 // In selects the frame called by the current frame.
516 func (p
*Process
) In() os
.Error
{
517 if p
.curGoroutine
== nil {
518 return NoCurrentGoroutine
{}
520 return p
.curGoroutine
.In()