OLD | NEW |
| (Empty) |
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. | |
4 | |
5 package ogle | |
6 | |
7 import ( | |
8 "debug/proc" | |
9 "exp/eval" | |
10 "fmt" | |
11 "os" | |
12 ) | |
13 | |
14 // A Goroutine represents a goroutine in a remote process. | |
15 type Goroutine struct { | |
16 g remoteStruct | |
17 frame *Frame | |
18 dead bool | |
19 } | |
20 | |
21 func (t *Goroutine) String() string { | |
22 if t.dead { | |
23 return "<dead thread>" | |
24 } | |
25 // TODO(austin) Give threads friendly ID's, possibly including | |
26 // the name of the entry function. | |
27 return fmt.Sprintf("thread %#x", t.g.addr().base) | |
28 } | |
29 | |
30 // isG0 returns true if this thread if the internal idle thread | |
31 func (t *Goroutine) isG0() bool { return t.g.addr().base == t.g.r.p.sys.g0.addr(
).base } | |
32 | |
33 func (t *Goroutine) resetFrame() (err os.Error) { | |
34 // TODO(austin) Reuse any live part of the current frame stack | |
35 // so existing references to Frame's keep working. | |
36 t.frame, err = newFrame(t.g) | |
37 return | |
38 } | |
39 | |
40 // Out selects the caller frame of the current frame. | |
41 func (t *Goroutine) Out() os.Error { | |
42 f, err := t.frame.Outer() | |
43 if f != nil { | |
44 t.frame = f | |
45 } | |
46 return err | |
47 } | |
48 | |
49 // In selects the frame called by the current frame. | |
50 func (t *Goroutine) In() os.Error { | |
51 f := t.frame.Inner() | |
52 if f != nil { | |
53 t.frame = f | |
54 } | |
55 return nil | |
56 } | |
57 | |
58 func readylockedBP(ev Event) (EventAction, os.Error) { | |
59 b := ev.(*Breakpoint) | |
60 p := b.Process() | |
61 | |
62 // The new g is the only argument to this function, so the | |
63 // stack will have the return address, then the G*. | |
64 regs, err := b.osThread.Regs() | |
65 if err != nil { | |
66 return EAStop, err | |
67 } | |
68 sp := regs.SP() | |
69 addr := sp + proc.Word(p.PtrSize()) | |
70 arg := remotePtr{remote{addr, p}, p.runtime.G} | |
71 var gp eval.Value | |
72 err = try(func(a aborter) { gp = arg.aGet(a) }) | |
73 if err != nil { | |
74 return EAStop, err | |
75 } | |
76 if gp == nil { | |
77 return EAStop, UnknownGoroutine{b.osThread, 0} | |
78 } | |
79 gs := gp.(remoteStruct) | |
80 g := &Goroutine{gs, nil, false} | |
81 p.goroutines[gs.addr().base] = g | |
82 | |
83 // Enqueue goroutine creation event | |
84 parent := b.Goroutine() | |
85 if parent.isG0() { | |
86 parent = nil | |
87 } | |
88 p.postEvent(&GoroutineCreate{commonEvent{p, g}, parent}) | |
89 | |
90 // If we don't have any thread selected, select this one | |
91 if p.curGoroutine == nil { | |
92 p.curGoroutine = g | |
93 } | |
94 | |
95 return EADefault, nil | |
96 } | |
97 | |
98 func goexitBP(ev Event) (EventAction, os.Error) { | |
99 b := ev.(*Breakpoint) | |
100 p := b.Process() | |
101 | |
102 g := b.Goroutine() | |
103 g.dead = true | |
104 | |
105 addr := g.g.addr().base | |
106 p.goroutines[addr] = nil, false | |
107 | |
108 // Enqueue thread exit event | |
109 p.postEvent(&GoroutineExit{commonEvent{p, g}}) | |
110 | |
111 // If we just exited our selected goroutine, selected another | |
112 if p.curGoroutine == g { | |
113 p.selectSomeGoroutine() | |
114 } | |
115 | |
116 return EADefault, nil | |
117 } | |
OLD | NEW |