Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: experimental/visual_studio_plugin/src/NaClVsx.Package/DebugSupport/NaClDebugger.cs

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 System.Linq;
11 using System.Runtime.CompilerServices;
12 using System.Threading;
13 using System.Xml.Linq;
14 using Google.MsAd7.BaseImpl.Interfaces;
15 using Google.NaClVsx.ProjectSupport;
16 using NaClVsx.DebugHelpers;
17
18 #endregion
19
20 namespace Google.NaClVsx.DebugSupport {
21 public sealed class NaClDebugger : INaClDebugger {
22 public NaClDebugger() {
23 BaseAddress = 0;
24 symbols_ = new NaClSymbolProvider(this);
25 }
26
27 public event SimpleDebuggerTypes.EventHandler Stopped;
28 public event SimpleDebuggerTypes.EventHandler StepFinished;
29 public event SimpleDebuggerTypes.EventHandler Continuing;
30 public event SimpleDebuggerTypes.MessageHandler Output;
31 public event SimpleDebuggerTypes.ModuleLoadHandler ModuleLoaded;
32 public event SimpleDebuggerTypes.MessageHandler Opened;
33
34 public string Arch { get; private set; }
35
36 public string Path { get; private set; }
37
38 #region INaClDebugger Members
39
40 public ulong BaseAddress { get; private set; }
41
42 [MethodImpl(MethodImplOptions.Synchronized)]
43 public void Open(string connectionString) {
44 sendStopMessages_ = false;
45 gdbProxy_.Open(connectionString);
46
47 // Can't set these until after Open() returns
48 gdbProxy_.SetStopAsync(OnGdbStop);
49 gdbProxy_.SetOutputAsync(OnGdbOutput);
50
51 var evt = new EventWaitHandle(false, EventResetMode.AutoReset);
52 gdbProxy_.GetArch(
53 (r, s, d) => {
54 if (GdbProxy.ResultCode.DHR_OK == r) {
55 ParseArchString(s);
56 }
57 evt.Set();
58 });
59 if (!evt.WaitOne(kGdbTimeout)) {
60 throw new TimeoutException("GDB connection timed out");
61 }
62
63 var regs = new RegsX86_64();
64 gdbProxy_.GetRegisters(ref regs);
65 BaseAddress = regs.R15;
66
67 var fullNexePath = NaClProjectConfig.GetLastNexe();
68 // note -- LoadModuleWithPath uses |BaseAddress| which we set
69 // above by reading register |R15|. Works only in x86-64 sandbox.
70 LoadModuleWithPath(fullNexePath);
71 /**
72 * TODO(mmortensen): In the future we may want to
73 * query sel_ldr for the nexe name (and full path?) to
74 * make sure we are running the nexe we built...esp
75 * when we are launching through chrome and using a server
76 * to run our app.
77 gdb_proxy_.GetPath(
78 (r, s, d) => {
79 status = r;
80 if (status == GdbProxy.ResultCode.DHR_OK && s!="") {
81 LoadModuleWithPath(s);
82 }
83 else if (s == "") {
84 // Set the path based on project data, as obtained from
85 // NaClProjectconfig.NexeList.
86 LoadModuleWithPath(full_nexe_path);
87 }
88 evt.Set();
89 });
90 if (!evt.WaitOne(gdbTimeout_)) {
91 throw new TimeoutException("GDB connection timed out");
92 }
93 **/
94 InvokeOpened(SimpleDebuggerTypes.ResultCode.Ok, Path);
95
96 sendStopMessages_ = true;
97 gdbWorkerThread_ = new System.Threading.Thread(GdbWorkerThreadProc);
98 gdbWorkerThread_.Name = "GDB Proxy Background Worker";
99 gdbWorkerThread_.Start();
100
101 // Debuggee is stopped at nexe entry point.
102 // Calling |GetLastSig| results in debugger getting notification about
103 // debuggee stopped status.
104 var lastSig = 0;
105 gdbProxy_.GetLastSig(out lastSig);
106 }
107
108 [MethodImpl(MethodImplOptions.Synchronized)]
109 public void Close() {
110 gdbTermEvent_.Set();
111 gdbProxy_.Close();
112 gdbWorkerThread_.Join(kGdbPingInterval * 8);
113 if (gdbWorkerThread_.IsAlive) {
114 gdbWorkerThread_.Abort();
115 }
116 gdbWorkerThread_ = null;
117 }
118
119 #endregion
120
121 #region Implementation of ISimpleDebugger
122
123 public string Architecture {
124 get { return Arch; }
125 }
126
127 public ISimpleSymbolProvider Symbols {
128 get { return symbols_; }
129 }
130
131 [MethodImpl(MethodImplOptions.Synchronized)]
132 public void Break() {
133 gdbProxy_.RequestBreak();
134 }
135
136 [MethodImpl(MethodImplOptions.Synchronized)]
137 public object GetRegisters(uint id) {
138 // FIXME -- |id| does NOT appear to be used by this function!!
139 // Note: |id| can be probably used to indicate register sets other than 'g eneral' registers.
140 // For example, set of SSE registers.
141 var regs = new RegsX86_64();
142 gdbProxy_.GetRegisters(ref regs);
143 if (regs.Rip == 0) {
144 Debug.WriteLine("ERROR: regs.RIPS is 0");
145 } else {
146 Debug.WriteLine("regs.RIPS is " + String.Format("{0,4:X}", regs.Rip));
147 }
148 Debug.WriteLine(
149 " GetRegisters.... Rip=" +
150 String.Format("{0,4:X}", regs.Rip) +
151 " Rsp=" + String.Format("{0,4:X}", regs.Rsp) +
152 " SegCS=" + String.Format("{0,4:X}", regs.SegCs) +
153 " SegDS=" + String.Format("{0,4:X}", regs.SegDs) +
154 " EFlags=" + String.Format("{0,4:X}", regs.EFlags));
155 return regs;
156 }
157
158 [MethodImpl(MethodImplOptions.Synchronized)]
159 public void Step(uint id) {
160 // SingleStep until
161 // - rip no longer points to the same source line.
162 // - some other thread throws a signal.
163 // - some signal other than STEP is thrown on this thread
164 //
165 // Some debugers might implement this a just a single step however,
166 // given the number of "NOP" required by the jump alignment, this
167 // could be painful, so instead we look for a different line.
168 var rip = ((RegsX86_64) GetRegisters(id)).Rip;
169 var pos = symbols_.PositionFromAddress(rip);
170
171 // Check if we are starting on a breakpoint. If so we need to
172 // temporarily remove it or we will immediately trigger a break
173 // without moving.
174 var bp = gdbProxy_.HasBreakpoint(rip);
175 if (StepFinished != null) {
176 StepFinished(
177 this,
178 SimpleDebuggerTypes.EventType.Step,
179 SimpleDebuggerTypes.ResultCode.Ok);
180 }
181
182 do {
183 // If we are on a breakpoint, temporarily remove it by
184 // stepping over it
185 if (bp) {
186 RemoveBreakpoint(rip);
187 sendStopMessages_ = false;
188 }
189 gdbProxy_.RequestStep();
190 if (bp) {
191 AddBreakpoint(rip);
192 sendStopMessages_ = true;
193
194 // We only need to check the first step, other BPs are valid
195 bp = false;
196 }
197
198 // If the signal is not a break trap, or if the thead changed
199 // something else triggered the stop, so we are done.
200 int sig;
201 gdbProxy_.GetLastSig(out sig);
202 if (sig != kTrapSignal)
203 break;
204
205 //TODO(noelallen) Add check for thread change...
206 //if (id != ) break;
207
208 rip = ((RegsX86_64) GetRegisters(id)).Rip;
209 } while (pos == symbols_.PositionFromAddress(rip));
210 }
211
212
213 [MethodImpl(MethodImplOptions.Synchronized)]
214 public void Continue() {
215 //TODO(noelallen) - use correct ID below
216 var regs = (RegsX86_64)GetRegisters(0);
217 var rip = regs.Rip;
218
219 Debug.WriteLine("CONTINUE, rip=0x" + String.Format("{0,4:X}", rip));
220 if (gdbProxy_.HasBreakpoint(rip)) {
221 Debug.WriteLine(
222 "NaClDebugger.cs, Continue()" +
223 "-HasBreakpoint = true, rip=" +
224 String.Format("{0,4:X}", rip));
225 RemoveBreakpoint(rip);
226 // First step one instruction, to prevent a race condition
227 // where the IP gets back to the current line before we have
228 // a chance to re-enable the breakpoint
229 sendStopMessages_ = false;
230 gdbProxy_.RequestStep();
231 sendStopMessages_ = true;
232 AddBreakpoint(rip);
233 } else {
234 Debug.WriteLine("NaClDebugger.cs, Continue()-HasBreakpoint = false");
235 }
236
237 var result = gdbProxy_.RequestContinue();
238 OnGdbContinue(result);
239 }
240
241 [MethodImpl(MethodImplOptions.Synchronized)]
242 public bool HasBreakpoint(ulong addr) {
243 return gdbProxy_.HasBreakpoint(addr);
244 }
245
246 [MethodImpl(MethodImplOptions.Synchronized)]
247 public void AddBreakpoint(ulong addr) {
248 gdbProxy_.AddBreakpoint(addr);
249 }
250
251 [MethodImpl(MethodImplOptions.Synchronized)]
252 public void RemoveBreakpoint(ulong addr) {
253 gdbProxy_.RemoveBreakpoint(addr);
254 }
255
256 [MethodImpl(MethodImplOptions.Synchronized)]
257 public void AddTempBreakpoint(ulong addr) {
258 // Don't if a real one exists
259 if (HasBreakpoint(addr)) {
260 return;
261 }
262 gdbProxy_.AddBreakpoint(addr);
263 tempBreakpoints_.Add(addr);
264 }
265
266 [MethodImpl(MethodImplOptions.Synchronized)]
267 public void RemoveTempBreakpoints() {
268 foreach (var addr in tempBreakpoints_) {
269 gdbProxy_.RemoveBreakpoint(addr);
270 }
271 tempBreakpoints_.Clear();
272 }
273
274 [MethodImpl(MethodImplOptions.Synchronized)]
275 public IEnumerable<uint> GetThreads() {
276 var evt = new EventWaitHandle(false, EventResetMode.AutoReset);
277 var tids = new List<uint>();
278 gdbProxy_.GetThreads(
279 (r, s, d) => {
280 if (GdbProxy.ResultCode.DHR_OK == r) {
281 ParseThreadsString(s, tids);
282 }
283 evt.Set();
284 });
285 evt.WaitOne();
286 return tids;
287 }
288
289 [MethodImpl(MethodImplOptions.Synchronized)]
290 public void GetMemory(ulong sourceAddress,
291 Array destination,
292 uint countInBytes) {
293 var result = gdbProxy_.GetMemory(sourceAddress, destination, countInBytes) ;
294 if (result != GdbProxy.ResultCode.DHR_OK) {
295 throw new ApplicationException("Failed GetMemory query");
296 }
297 }
298
299 [MethodImpl(MethodImplOptions.Synchronized)]
300 public void SetMemory(ulong destAddress, Array src, uint count) {
301 var result = gdbProxy_.SetMemory(destAddress, src, count);
302 if (result != GdbProxy.ResultCode.DHR_OK) {
303 throw new ApplicationException("Failed SetMemory query");
304 }
305 }
306
307 public ulong GetU64(ulong address) {
308 var data = new byte[8];
309 GetMemory(address, data, 8);
310 return BitConverter.ToUInt64(data, 0);
311 }
312
313 public uint GetU32(ulong address) {
314 var data = new byte[4];
315 GetMemory(address, data, 4);
316 return BitConverter.ToUInt32(data, 0);
317 }
318
319 #endregion
320
321 #region Private Implementation
322
323 private readonly EventWaitHandle gdbTermEvent_ =
324 new EventWaitHandle(false, EventResetMode.ManualReset);
325
326 private readonly GdbProxy gdbProxy_ = new GdbProxy();
327 private readonly NaClSymbolProvider symbols_;
328 private readonly List<ulong> tempBreakpoints_ = new List<ulong>();
329
330 private const int kGdbPingInterval = 1000; // in ms
331 private const int kGdbTimeout = 10000; // in ms
332 private const int kTrapSignal = 5;
333 private System.Threading.Thread gdbWorkerThread_;
334 private bool sendStopMessages_ = true;
335
336 #endregion
337
338 #region Private Implementation
339
340 private void GdbWorkerThreadProc() {
341 do {
342 lock (this) {
343 // gdb_proxy_::RequestContinue is not blocking anymore, so this worker thread
344 // has to poll RSP connection for reply (sent by debug server when deb uggee
345 // stops for some reason).
346 // gdb_proxy_.WaitForReply will notify callback registered by gdb_prox y_.SetStopAsync.
347 if (gdbProxy_.IsRunning())
348 gdbProxy_.WaitForReply();
349 }
350 } while (gdbTermEvent_.WaitOne(kGdbPingInterval * 1) == false);
351 }
352
353 private void InvokeOpened(SimpleDebuggerTypes.ResultCode status, string msg) {
354 var handler = Opened;
355 if (handler != null) {
356 handler(this, status, msg);
357 }
358 }
359
360 private void LoadModuleWithPath(string fullPathToNexe) {
361 string status;
362 Path = fullPathToNexe;
363 Debug.WriteLine("LoadModuleWithPath {" + Path + "}");
364 symbols_.LoadModule(Path, BaseAddress, out status);
365 if (ModuleLoaded != null) {
366 ModuleLoaded(this, Path, status);
367 }
368 }
369
370 private void OnGdbContinue(GdbProxy.ResultCode result) {
371 if (Continuing != null) {
372 Continuing(
373 this,
374 SimpleDebuggerTypes.EventType.Continue,
375 (SimpleDebuggerTypes.ResultCode) result);
376 }
377 }
378
379 private void OnGdbOutput(GdbProxy.ResultCode result, string msg, byte[] data ) {
380 if (Output != null) {
381 Output(this, (SimpleDebuggerTypes.ResultCode) result, msg);
382 }
383 }
384
385 private void OnGdbStop(GdbProxy.ResultCode result, string msg, byte[] data) {
386 RemoveTempBreakpoints();
387
388 if (sendStopMessages_ && Stopped != null) {
389 Debug.WriteLine("Sending stopped message");
390 Stopped(
391 this,
392 SimpleDebuggerTypes.EventType.Break,
393 (SimpleDebuggerTypes.ResultCode) result);
394 }
395 }
396
397 private void ParseArchString(string msg) {
398 Debug.WriteLine(msg);
399 try {
400 var targetString = XElement.Parse(msg);
401 var archElements =
402 targetString.Descendants("architecture");
403 var el = archElements.FirstOrDefault();
404 Arch = el.Value;
405 }
406 catch (Exception e) {
407 Debug.WriteLine(e.Message);
408 }
409 }
410
411 private void ParseThreadsString(string msg, List<uint> tids) {
412 Debug.WriteLine(msg);
413 try {
414 var threadsString = XElement.Parse(msg);
415 foreach (var el in threadsString.Descendants("thread")) {
416 var tidStr = el.Attribute("id").Value;
417 var tid = Convert.ToUInt32(tidStr, 16);
418
419 tids.Add(tid);
420 }
421 }
422 catch (Exception e) {
423 Debug.WriteLine(e.Message);
424 }
425 }
426
427 #endregion
428 }
429 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698