Skip to content

Commit eb98b74

Browse files
committed
implement DAP Goto Request
1 parent 5739661 commit eb98b74

File tree

10 files changed

+151
-31
lines changed

10 files changed

+151
-31
lines changed

src/MICore/CommandFactories/MICommandFactory.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ public async Task ExecNextInstruction(int threadId, ResultClass resultClass = Re
242242
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
243243
}
244244

245+
/// <summary>
246+
/// Jumps to a specified target location
247+
/// </summary>
248+
abstract public Task ExecJump(string filename, int line);
249+
abstract public Task ExecJump(ulong address);
250+
245251
/// <summary>
246252
/// Tells GDB to spawn a target process previous setup with -file-exec-and-symbols or similar
247253
/// </summary>

src/MICore/CommandFactories/gdb.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public override async Task<Results> ThreadInfo(uint? threadId = null)
157157

158158
public override async Task<List<ulong>> StartAddressesForLine(string file, uint line)
159159
{
160-
string cmd = "info line " + file + ":" + line;
160+
string cmd = "info line -s " + file + " -li " + line;
161161
var result = await _debugger.ConsoleCmdAsync(cmd, allowWhileRunning: false);
162162
List<ulong> addresses = new List<ulong>();
163163
using (StringReader stringReader = new StringReader(result))
@@ -173,7 +173,7 @@ public override async Task<List<ulong>> StartAddressesForLine(string file, uint
173173
{
174174
ulong address;
175175
string addrStr = resultLine.Substring(pos + 18);
176-
if (MICommandFactory.SpanNextAddr(addrStr, out address) != null)
176+
if (SpanNextAddr(addrStr, out address) != null)
177177
{
178178
addresses.Add(address);
179179
}
@@ -183,6 +183,28 @@ public override async Task<List<ulong>> StartAddressesForLine(string file, uint
183183
return addresses;
184184
}
185185

186+
private async Task JumpInternal(string target)
187+
{
188+
// temporary breakpoint + jump
189+
// NB: the gdb docs state: "Resume execution at line linespec. Execution stops again immediately if there is a breakpoint there."
190+
// We rely on this. If another thread hits a breakpoint before that we have a UX problem
191+
// and would need to handle this via scheduler-locking for all-stop mode and ??? for non-stop mode.
192+
await _debugger.CmdAsync("-break-insert -t " + target, ResultClass.done);
193+
await _debugger.CmdAsync("-exec-jump " + target, ResultClass.running);
194+
}
195+
196+
public override Task ExecJump(string filename, int line)
197+
{
198+
string target = "--source " + filename + " --line " + line.ToString(CultureInfo.InvariantCulture);
199+
return JumpInternal(target);
200+
}
201+
202+
public override Task ExecJump(ulong address)
203+
{
204+
string target = "*" + string.Format(CultureInfo.InvariantCulture, "0x{0:X}", address);
205+
return JumpInternal(target);
206+
}
207+
186208
public override Task EnableTargetAsyncOption()
187209
{
188210
// Linux attach TODO: GDB will fail this command when attaching. This is worked around

src/MICore/CommandFactories/lldb.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ public override Task Catch(string name, bool onlyOnce = false, ResultClass resul
177177
throw new NotImplementedException("lldb catch command");
178178
}
179179

180+
// TODO: update these if they become available in lldb-mi
181+
public override async Task ExecJump(string filename, int line)
182+
{
183+
string command = "jump " + filename + ":" + line;
184+
await _debugger.CmdAsync(command, ResultClass.running);
185+
}
186+
187+
public override async Task ExecJump(ulong address)
188+
{
189+
string command = "jump *" + string.Format(CultureInfo.InvariantCulture, "0x{0:X}", address);
190+
await _debugger.CmdAsync(command, ResultClass.running);
191+
}
192+
180193
/// <summary>
181194
/// Assigns the value of an expression to a variable.
182195
/// Since LLDB only accepts assigning values to variables, the expression may need to be evaluated.

src/MIDebugEngine/AD7.Impl/AD7Engine.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,44 @@ public object GetMetric(string metric)
182182
return _configStore.GetEngineMetric(metric);
183183
}
184184

185+
public int Jump(string filename, int line)
186+
{
187+
try
188+
{
189+
_debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Jump(filename, line));
190+
}
191+
catch (InvalidCoreDumpOperationException)
192+
{
193+
return AD7_HRESULT.E_CRASHDUMP_UNSUPPORTED;
194+
}
195+
catch (Exception e)
196+
{
197+
_engineCallback.OnError(EngineUtils.GetExceptionDescription(e));
198+
return Constants.E_ABORT;
199+
}
200+
201+
return Constants.S_OK;
202+
}
203+
204+
public int Jump(ulong address)
205+
{
206+
try
207+
{
208+
_debuggedProcess.WorkerThread.RunOperation(() => _debuggedProcess.Jump(address));
209+
}
210+
catch (InvalidCoreDumpOperationException)
211+
{
212+
return AD7_HRESULT.E_CRASHDUMP_UNSUPPORTED;
213+
}
214+
catch (Exception e)
215+
{
216+
_engineCallback.OnError(EngineUtils.GetExceptionDescription(e));
217+
return Constants.E_ABORT;
218+
}
219+
220+
return Constants.S_OK;
221+
}
222+
185223
#region IDebugEngine2 Members
186224

187225
// Attach the debug engine to a program.

src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
198198
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION;
199199
}
200200
}
201+
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0)
202+
{
203+
// TODO:
204+
}
201205

202206
return Constants.S_OK;
203207
}

src/MIDebugEngine/AD7.Impl/AD7Thread.cs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -282,27 +282,23 @@ int IDebugThread2.Resume(out uint suspendCount)
282282
}
283283

284284
// Sets the next statement to the given stack frame and code context.
285+
// https://docs.microsoft.com/en-us/visualstudio/extensibility/debugger/reference/idebugthread2-setnextstatement
285286
int IDebugThread2.SetNextStatement(IDebugStackFrame2 stackFrame, IDebugCodeContext2 codeContext)
286287
{
287-
ulong addr = ((AD7MemoryAddress)codeContext).Address;
288-
AD7StackFrame frame = ((AD7StackFrame)stackFrame);
289-
if (frame.ThreadContext.Level != 0 || frame.Thread != this || !frame.ThreadContext.pc.HasValue)
290-
{
288+
// VS does provide a frame so at least do some sanity checks
289+
AD7StackFrame frame = stackFrame as AD7StackFrame;
290+
if (frame != null && (frame.ThreadContext.Level != 0 || frame.Thread != this))
291291
return Constants.S_FALSE;
292-
}
293-
string toFunc = EngineUtils.GetAddressDescription(_engine.DebuggedProcess, addr);
294-
string fromFunc = EngineUtils.GetAddressDescription(_engine.DebuggedProcess, frame.ThreadContext.pc.Value);
295-
if (toFunc != fromFunc)
292+
293+
try
296294
{
297-
return Constants.S_FALSE;
295+
ulong addr = ((AD7MemoryAddress)codeContext).Address;
296+
return _engine.Jump(addr);
298297
}
299-
string result = frame.EvaluateExpression("$pc=" + EngineUtils.AsAddr(addr, _engine.DebuggedProcess.Is64BitArch));
300-
if (result != null)
298+
catch (Exception)
301299
{
302-
_engine.DebuggedProcess.ThreadCache.MarkDirty();
303-
return Constants.S_OK;
300+
return Constants.S_FALSE;
304301
}
305-
return Constants.S_FALSE;
306302
}
307303

308304
// suspend a thread.

src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,6 +1631,16 @@ public Task Continue(DebuggedThread thread)
16311631
return Execute(thread);
16321632
}
16331633

1634+
public async Task Jump(string filename, int line)
1635+
{
1636+
await MICommandFactory.ExecJump(filename, line);
1637+
}
1638+
1639+
public async Task Jump(ulong address)
1640+
{
1641+
await MICommandFactory.ExecJump(address);
1642+
}
1643+
16341644
public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit)
16351645
{
16361646
this.VerifyNotDebuggingCoreDump();

src/OpenDebugAD7/AD7DebugSession.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,37 @@ protected override void HandlePauseRequestAsync(IRequestResponder<PauseArguments
13371337

13381338
protected override void HandleGotoRequestAsync(IRequestResponder<GotoArguments> responder)
13391339
{
1340-
responder.SetError(new ProtocolException(AD7Resources.Error_NotImplementedSetNextStatement));
1340+
var response = new GotoResponse();
1341+
if (!m_isStopped)
1342+
{
1343+
responder.SetResponse(response);
1344+
return;
1345+
}
1346+
1347+
var builder = new ErrorBuilder(() => AD7Resources.Error_UnableToSetNextStatement);
1348+
IDebugThread2 thread = null;
1349+
try
1350+
{
1351+
if (m_gotoCodeContexts.TryGetValue(responder.Arguments.TargetId, out IDebugCodeContext2 gotoTarget))
1352+
{
1353+
lock (m_threads)
1354+
{
1355+
if (!m_threads.TryGetValue(responder.Arguments.ThreadId, out thread))
1356+
throw new AD7Exception("Unknown thread id: " + responder.Arguments.ThreadId.ToString(CultureInfo.InvariantCulture));
1357+
}
1358+
BeforeContinue();
1359+
builder.CheckHR(thread.SetNextStatement(null, gotoTarget));
1360+
}
1361+
}
1362+
catch (AD7Exception e)
1363+
{
1364+
m_isStopped = true;
1365+
responder.SetError(new ProtocolException(e.Message));
1366+
return;
1367+
}
1368+
1369+
responder.SetResponse(response);
1370+
FireStoppedEvent(thread, StoppedEvent.ReasonValue.Goto);
13411371
}
13421372

13431373
protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTargetsArguments, GotoTargetsResponse> responder)
@@ -1347,6 +1377,7 @@ protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTarg
13471377
var source = responder.Arguments.Source;
13481378

13491379
// Virtual documents don't have paths
1380+
// TODO: handle this for disassembly debugging
13501381
if (source.Path == null)
13511382
{
13521383
responder.SetResponse(response);
@@ -1369,10 +1400,8 @@ protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTarg
13691400
while (codeContextsEnum.Next(1, codeContexts, ref nProps) == HRConstants.S_OK)
13701401
{
13711402
var codeContext = codeContexts[0];
1372-
13731403
string contextName;
13741404
codeContext.GetName(out contextName);
1375-
13761405
line = responder.Arguments.Line;
13771406
IDebugDocumentContext2 documentContext;
13781407
if (codeContext.GetDocumentContext(out documentContext) == HRConstants.S_OK)

src/OpenDebugAD7/AD7Resources.Designer.cs

Lines changed: 11 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/OpenDebugAD7/AD7Resources.resx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@
195195
<data name="Error_UnableToSetBreakpoint" xml:space="preserve">
196196
<value>Error setting breakpoint. {0}</value>
197197
</data>
198+
<data name="Error_UnableToSetNextStatement" xml:space="preserve">
199+
<value>Error setting next statement. {0}</value>
200+
</data>
198201
<data name="Error_UnableToParseLogMessage" xml:space="preserve">
199202
<value>Unable to parse 'logMessage'.</value>
200203
</data>
@@ -298,7 +301,4 @@
298301
<data name="Error_Scenario_StackTrace" xml:space="preserve">
299302
<value>Unable to retrieve stack trace. {0}</value>
300303
</data>
301-
<data name="Error_NotImplementedSetNextStatement" xml:space="preserve">
302-
<value>Set next statement is not supported by the current debugger.</value>
303-
</data>
304304
</root>

0 commit comments

Comments
 (0)