Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / exp / ogle / process.go
blob58e830aa68bfcd9595ebed406db3b46e670665fa
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.
5 package ogle
7 import (
8 "debug/elf"
9 "debug/gosym"
10 "debug/proc"
11 "exp/eval"
12 "fmt"
13 "log"
14 "os"
15 "reflect"
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 {
42 OSThread proc.Thread
43 Goroutine proc.Word
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
52 // process).
53 type NoCurrentGoroutine struct{}
55 func (e NoCurrentGoroutine) String() string { return "no current goroutine" }
57 // A Process represents a remote attached process.
58 type Process struct {
59 Arch
60 proc proc.Process
62 // The symbol table of this process
63 syms *gosym.Table
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
72 runtime runtimeValues
74 // Runtime field indexes
75 f runtimeIndexes
77 // Globals from the sys package (or from no package)
78 sys struct {
79 lessstack, goexit, newproc, deferproc, newprocreadylocked *gosym.Func
80 allg remotePtr
81 g0 remoteStruct
84 // Event queue
85 posted []Event
86 pending []Event
87 event Event
89 // Event hooks
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
102 * Process creation
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) {
108 p := &Process{
109 Arch: arch,
110 proc: tproc,
111 syms: syms,
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
120 p.bootstrap()
122 switch {
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)
137 for g != nil {
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)
144 if err != nil {
145 return nil, err
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 {
154 g.resetFrame()
157 p.selectSomeGoroutine()
159 return p, nil
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 {
167 return nil, nil
170 symdat, err := symtab.Data()
171 if err != nil {
172 return nil, err
174 pclndat, err := pclntab.Data()
175 if err != nil {
176 return nil, err
179 pcln := gosym.NewLineTable(pclndat, text.Addr)
180 tab, err := gosym.NewTable(symdat, pcln)
181 if err != nil {
182 return nil, err
185 return tab, nil
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)
192 if err != nil {
193 return nil, err
195 if syms == nil {
196 return nil, FormatError("Failed to find symbol table")
198 var arch Arch
199 switch f.Machine {
200 case elf.EM_X86_64:
201 arch = Amd64
202 default:
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' {
234 continue
236 sym := p.syms.LookupSym("type.*runtime." + n[1:])
237 if sym == nil {
238 continue
240 rtv.Field(i).(*reflect.UintValue).Set(sym.Value)
243 // Get runtime field indexes
244 fillRuntimeIndexes(&p.runtime, &p.f)
246 // Fill G status
247 p.runtime.runtimeGStatus = rt1GStatus
249 // Get globals
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.
266 p.curGoroutine = nil
267 for _, g := range p.goroutines {
268 if !g.isG0() && g.frame != nil {
269 p.curGoroutine = g
270 return
276 * Process memory
279 func (p *Process) someStoppedOSThread() proc.Thread {
280 if p.threadCache != nil {
281 if _, err := p.threadCache.Stopped(); err == nil {
282 return p.threadCache
286 for _, t := range p.proc.Threads() {
287 if _, err := t.Stopped(); err == nil {
288 p.threadCache = t
289 return t
292 return nil
295 func (p *Process) Peek(addr proc.Word, out []byte) (int, os.Error) {
296 thr := p.someStoppedOSThread()
297 if thr == nil {
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()
305 if thr == nil {
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))
316 * Events
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 {
323 return bp
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()
340 if err != nil {
341 return nil, err
343 g := p.G(regs)
344 gt, ok := p.goroutines[g]
345 if !ok {
346 return nil, UnknownGoroutine{t, g}
348 return gt, nil
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
355 nev := 0
356 for _, t := range p.proc.Threads() {
357 if c, err := t.Stopped(); err == nil {
358 switch c := c.(type) {
359 case proc.Breakpoint:
360 nev++
361 case proc.Signal:
362 // TODO(austin)
363 //nev++;
368 // Translate causes to events
369 events := make([]Event, nev)
370 i := 0
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)
376 if err != nil {
377 return nil, err
379 events[i] = &Breakpoint{commonEvent{p, gt}, t, proc.Word(c)}
381 case proc.Signal:
382 // TODO(austin)
387 return events, nil
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) {
400 var ev Event
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 {
405 return action, err
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 {
413 return action, err
417 return EAContinue, nil
420 // processEvent processes a single event, without manipulating the
421 // event queues. It returns either EAStop or EAContinue and possibly
422 // an error.
423 func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
424 p.event = ev
426 var action EventAction
427 var err os.Error
428 switch ev := p.event.(type) {
429 case *Breakpoint:
430 hook, ok := p.breakpointHooks[ev.pc]
431 if !ok {
432 break
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)
441 case *GoroutineExit:
442 action, err = p.goroutineExitHook.handle(ev)
444 default:
445 log.Panicf("Unknown event type %T in queue", p.event)
448 if err != nil {
449 return EAStop, err
450 } else if action == EAStop {
451 return EAStop, nil
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 }
463 * Process control
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 {
481 for {
482 a, err := p.processEvents()
483 if err != nil {
484 return err
485 } else if a == EAStop {
486 break
488 err = p.proc.Continue()
489 if err != nil {
490 return err
492 err = p.proc.WaitStop()
493 if err != nil {
494 return err
496 for _, g := range p.goroutines {
497 g.resetFrame()
499 p.pending, err = p.causesToEvents()
500 if err != nil {
501 return err
504 return nil
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()