OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #region | |
6 | |
7 using System; | |
8 using System.Collections.Generic; | |
9 using System.Diagnostics; | |
10 using Google.MsAd7.BaseImpl; | |
11 using Google.MsAd7.BaseImpl.Ad7Enumerators; | |
12 using Google.MsAd7.BaseImpl.DebugProperties; | |
13 using Microsoft.VisualStudio; | |
14 using Microsoft.VisualStudio.Debugger.Interop; | |
15 using NaClVsx.DebugHelpers; | |
16 using StackFrame = Google.MsAd7.BaseImpl.StackFrame; | |
17 | |
18 #endregion | |
19 | |
20 namespace Google.NaClVsx.DebugSupport { | |
21 public class Thread : IDebugThread2 { | |
22 public Thread(ProgramNode program, string name, uint tid) { | |
23 name_ = name; | |
24 tid_ = tid; | |
25 program_ = program; | |
26 } | |
27 | |
28 #region Implementation of IDebugThread2 | |
29 | |
30 public List<StackFrame> GetStack() { | |
31 return stack_; | |
32 } | |
33 | |
34 /// <summary> | |
35 /// Called by the Visual Studio Debugger to retrieve the stack frames for | |
36 /// this thread. On halt, this will be called on each thread. Detailed | |
37 /// information about the arguments and required usage can be found on | |
38 /// msdn. | |
39 /// </summary> | |
40 public int EnumFrameInfo(enum_FRAMEINFO_FLAGS dwFieldSpec, | |
41 uint nRadix, | |
42 out IEnumDebugFrameInfo2 ppEnum) { | |
43 Debug.WriteLine("Thread.EnumFrameInfo"); | |
44 | |
45 RefreshFrameInfo(stack_); | |
46 | |
47 var frames = new List<FRAMEINFO>(stack_.Count); | |
48 var fi = new FRAMEINFO[1]; | |
49 | |
50 foreach (var stackFrame in stack_) { | |
51 stackFrame.GetInfo(dwFieldSpec, nRadix, fi); | |
52 frames.Add(fi[0]); | |
53 } | |
54 | |
55 ppEnum = new FrameInfoEnumerator(frames); | |
56 | |
57 return VSConstants.S_OK; | |
58 } | |
59 | |
60 public int GetName(out string pbstrName) { | |
61 Debug.WriteLine("Thread.GetName"); | |
62 pbstrName = name_; | |
63 return VSConstants.S_OK; | |
64 } | |
65 | |
66 public int SetThreadName(string pszName) { | |
67 Debug.WriteLine("Thread.SetThreadName"); | |
68 name_ = pszName; | |
69 return VSConstants.S_OK; | |
70 } | |
71 | |
72 public int GetProgram(out IDebugProgram2 ppProgram) { | |
73 Debug.WriteLine("Thread.GetProgram"); | |
74 ppProgram = program_; | |
75 return VSConstants.S_OK; | |
76 } | |
77 | |
78 public int CanSetNextStatement(IDebugStackFrame2 pStackFrame, | |
79 IDebugCodeContext2 pCodeContext) { | |
80 Debug.WriteLine("Thread.CanSetNextStatement"); | |
81 | |
82 // For now, we just don't support this. | |
83 return VSConstants.S_FALSE; | |
84 } | |
85 | |
86 public int SetNextStatement(IDebugStackFrame2 pStackFrame, | |
87 IDebugCodeContext2 pCodeContext) { | |
88 Debug.WriteLine("Thread.SetNextStatement"); | |
89 throw new NotImplementedException(); | |
90 } | |
91 | |
92 public int GetThreadId(out uint pdwThreadId) { | |
93 Debug.WriteLine("Thread.GetThreadId"); | |
94 pdwThreadId = tid_; | |
95 return VSConstants.S_OK; | |
96 } | |
97 | |
98 public int Suspend(out uint pdwSuspendCount) { | |
99 Debug.WriteLine("Thread.Suspend"); | |
100 throw new NotImplementedException(); | |
101 } | |
102 | |
103 public int Resume(out uint pdwSuspendCount) { | |
104 Debug.WriteLine("Thread.Resume"); | |
105 throw new NotImplementedException(); | |
106 } | |
107 | |
108 public int GetThreadProperties(enum_THREADPROPERTY_FIELDS dwFields, | |
109 THREADPROPERTIES[] ptp) { | |
110 Debug.WriteLine("Thread.GetThreadProperties"); | |
111 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_ID)) { | |
112 ptp[0].dwThreadId = tid_; | |
113 } | |
114 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_NAME)) { | |
115 ptp[0].bstrName = name_; | |
116 } | |
117 | |
118 // The following properties are currently bogus. | |
119 // | |
120 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_LOCATION)) { | |
121 ptp[0].bstrLocation = "THREADPROPERTY: Location"; | |
122 } | |
123 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_PRIORITY)) { | |
124 ptp[0].bstrPriority = "THREADPROPERTY: Priority"; | |
125 } | |
126 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_STATE)) { | |
127 ptp[0].dwThreadState = (uint) enum_THREADSTATE.THREADSTATE_STOPPED; | |
128 } | |
129 if (dwFields.HasFlag(enum_THREADPROPERTY_FIELDS.TPF_SUSPENDCOUNT)) { | |
130 ptp[0].dwSuspendCount = 1; | |
131 } | |
132 | |
133 ptp[0].dwFields = dwFields; | |
134 | |
135 return VSConstants.S_OK; | |
136 } | |
137 | |
138 public int GetLogicalThread(IDebugStackFrame2 pStackFrame, | |
139 out IDebugLogicalThread2 ppLogicalThread) { | |
140 Debug.WriteLine("Thread.GetLogicalThread"); | |
141 throw new NotImplementedException(); | |
142 } | |
143 | |
144 #endregion | |
145 | |
146 #region Private Implementation | |
147 | |
148 private readonly ProgramNode program_; | |
149 | |
150 private readonly List<StackFrame> stack_ = new List<StackFrame>(); | |
151 private readonly uint tid_; | |
152 private string name_; | |
153 | |
154 #endregion | |
155 | |
156 /// <summary> | |
157 /// Gets the frame information for the current stack frame. This means | |
158 /// getting a snapshot of the register state for each each frame in the | |
159 /// stack so that memory address information can be derived at a later | |
160 /// stage. | |
161 /// </summary> | |
162 /// <param name = "stack"></param> | |
163 protected void RefreshFrameInfo(List<StackFrame> stack) { | |
164 stack.Clear(); | |
165 var regs = (RegsX86_64) program_.Dbg.GetRegisters(tid_); | |
166 var rset = new RegisterSet(RegisterSetSchema.DwarfAmd64Integer, null); | |
167 | |
168 // TODO: need a less hacky way to initialize a RegisterSet from a | |
169 // RegsX86_64. | |
170 foreach ( | |
171 var registerDef in | |
172 RegisterSetSchema.DwarfAmd64Integer.Registers) { | |
173 if (!registerDef.Pseudo) { | |
174 rset[registerDef.Index] = regs[registerDef.Index]; | |
175 } | |
176 } | |
177 while (rset["RIP"] != 0) { | |
178 stack.Add(new StackFrame(rset, this, program_.MainModule, program_.Dbg))
; | |
179 // Get the register values of the previous frame. | |
180 var sym = program_.Dbg.Symbols as NaClSymbolProvider; | |
181 var nextRset = sym.GetPreviousFrameState(rset); | |
182 // The toolchain creates a dummy frame at the outermost scope. Gdb | |
183 // has some way to get past the dummy frame, but strict application of | |
184 // the DWARF spec makes it look circular to us. TODO: investigate why | |
185 if (nextRset == null || nextRset["RIP"] == rset["RIP"]) { | |
186 break; | |
187 } | |
188 rset = nextRset; | |
189 } | |
190 } | |
191 } | |
192 } | |
OLD | NEW |