Skip to content

Commit a4cdd47

Browse files
committed
implement Goto Request
1 parent e1b8dda commit a4cdd47

File tree

11 files changed

+219
-34
lines changed

11 files changed

+219
-34
lines changed

src/MICore/CommandFactories/MICommandFactory.cs

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

249+
/// <summary>
250+
/// Jumps to a specified target location
251+
/// </summary>
252+
abstract public Task ExecJump(string filename, int line);
253+
abstract public Task ExecJump(ulong address);
254+
249255
/// <summary>
250256
/// Tells GDB to spawn a target process previous setup with -file-exec-and-symbols or similar
251257
/// </summary>

src/MICore/CommandFactories/clrdbg.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,16 @@ public override Task Catch(string name, bool onlyOnce = false, ResultClass resul
237237
throw new NotImplementedException("clrdbg catch command");
238238
}
239239

240+
public override Task ExecJump(string filename, int line)
241+
{
242+
throw new NotImplementedException("clrdbg jump command");
243+
}
244+
245+
public override Task ExecJump(ulong address)
246+
{
247+
throw new NotImplementedException("clrdbg jump command");
248+
}
249+
240250
public override string GetTargetArchitectureCommand()
241251
{
242252
return null;

src/MICore/CommandFactories/gdb.cs

Lines changed: 21 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,25 @@ 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+
await _debugger.CmdAsync("-break-insert -t " + target, ResultClass.done);
190+
await _debugger.CmdAsync("-exec-jump " + target, ResultClass.running);
191+
}
192+
193+
public override Task ExecJump(string filename, int line)
194+
{
195+
string target = "--source " + filename + " --line " + line.ToString(CultureInfo.InvariantCulture);
196+
return JumpInternal(target);
197+
}
198+
199+
public override Task ExecJump(ulong address)
200+
{
201+
string target = "*" + string.Format(CultureInfo.InvariantCulture, "0x{0:X}", address);
202+
return JumpInternal(target);
203+
}
204+
186205
public override Task EnableTargetAsyncOption()
187206
{
188207
// 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("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
@@ -187,6 +187,44 @@ public object GetMetric(string metric)
187187
return _configStore.GetEngineMetric(metric);
188188
}
189189

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

192230
// Attach the debug engine to a program.

src/MIDebugEngine/AD7.Impl/AD7MemoryAddress.cs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5-
using System.Collections.Generic;
6-
using System.Text;
75
using Microsoft.VisualStudio.Debugger.Interop;
86
using MICore;
9-
using Microsoft.MIDebugEngine.Natvis;
107

118
namespace Microsoft.MIDebugEngine
129
{
1310
// And implementation of IDebugCodeContext2 and IDebugMemoryContext2.
1411
// IDebugMemoryContext2 represents a position in the address space of the machine running the program being debugged.
1512
// IDebugCodeContext2 represents the starting position of a code instruction.
1613
// For most run-time architectures today, a code context can be thought of as an address in a program's execution stream.
17-
internal class AD7MemoryAddress : IDebugCodeContext2
14+
internal sealed class AD7MemoryAddress : IDebugCodeContext2
1815
{
1916
private readonly AD7Engine _engine;
2017
private readonly ulong _address;
@@ -42,6 +39,7 @@ public void SetDocumentContext(IDebugDocumentContext2 docContext)
4239
// Adds a specified value to the current context's address to create a new context.
4340
public int Add(ulong dwCount, out IDebugMemoryContext2 newAddress)
4441
{
42+
// FIXME: this is not correct for IDebugCodeContext2
4543
newAddress = new AD7MemoryAddress(_engine, (uint)dwCount + _address, null);
4644
return Constants.S_OK;
4745
}
@@ -160,19 +158,15 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
160158
{
161159
pinfo[0].dwFields = 0;
162160

163-
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0)
161+
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS) != 0 ||
162+
(dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0)
164163
{
165164
pinfo[0].bstrAddress = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch);
166-
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS;
165+
pinfo[0].bstrAddressAbsolute = pinfo[0].bstrAddress;
166+
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS | enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE;
167167
}
168-
169168
// Fields not supported by the sample
170169
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSOFFSET) != 0) { }
171-
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE) != 0)
172-
{
173-
pinfo[0].bstrAddressAbsolute = EngineUtils.AsAddr(_address, _engine.DebuggedProcess.Is64BitArch);
174-
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_ADDRESSABSOLUTE;
175-
}
176170
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_MODULEURL) != 0)
177171
{
178172
DebuggedModule module = _engine.DebuggedProcess.ResolveAddress(_address);
@@ -195,7 +189,10 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
195189
pinfo[0].dwFields |= enum_CONTEXT_INFO_FIELDS.CIF_FUNCTION;
196190
}
197191
}
198-
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0) { }
192+
if ((dwFields & enum_CONTEXT_INFO_FIELDS.CIF_FUNCTIONOFFSET) != 0)
193+
{
194+
// TODO:
195+
}
199196

200197
return Constants.S_OK;
201198
}
@@ -210,10 +207,10 @@ public int GetInfo(enum_CONTEXT_INFO_FIELDS dwFields, CONTEXT_INFO[] pinfo)
210207
}
211208

212209
// Gets the user-displayable name for this context
213-
// This is not supported by the sample engine.
214210
public int GetName(out string pbstrName)
215211
{
216-
throw new NotImplementedException();
212+
pbstrName = _functionName ?? Engine.GetAddressDescription(_address);
213+
return Constants.S_OK;
217214
}
218215

219216
// Subtracts a specified value from the current context's address to create a new context.

src/MIDebugEngine/AD7.Impl/AD7Thread.cs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -276,26 +276,19 @@ int IDebugThread2.Resume(out uint suspendCount)
276276
// Sets the next statement to the given stack frame and code context.
277277
int IDebugThread2.SetNextStatement(IDebugStackFrame2 stackFrame, IDebugCodeContext2 codeContext)
278278
{
279-
// CLRDBG TODO: This implementation should be changed to call an MI command
280-
ulong addr = ((AD7MemoryAddress)codeContext).Address;
281-
AD7StackFrame frame = ((AD7StackFrame)stackFrame);
282-
if (frame.ThreadContext.Level != 0 || frame.Thread != this || !frame.ThreadContext.pc.HasValue || _engine.DebuggedProcess.MICommandFactory.Mode == MIMode.Clrdbg)
283-
{
279+
var infos = new CONTEXT_INFO[1];
280+
if (codeContext.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, infos) != Constants.S_OK)
284281
return Constants.S_FALSE;
285-
}
286-
string toFunc = EngineUtils.GetAddressDescription(_engine.DebuggedProcess, addr);
287-
string fromFunc = EngineUtils.GetAddressDescription(_engine.DebuggedProcess, frame.ThreadContext.pc.Value);
288-
if (toFunc != fromFunc)
282+
283+
try
289284
{
290-
return Constants.S_FALSE;
285+
ulong address = Convert.ToUInt64(infos[0].bstrAddress, 16);
286+
return _engine.Jump(address);
291287
}
292-
string result = frame.EvaluateExpression("$pc=" + EngineUtils.AsAddr(addr, _engine.DebuggedProcess.Is64BitArch));
293-
if (result != null)
288+
catch (Exception)
294289
{
295-
_engine.DebuggedProcess.ThreadCache.MarkDirty();
296-
return Constants.S_OK;
290+
return Constants.S_FALSE;
297291
}
298-
return Constants.S_FALSE;
299292
}
300293

301294
// suspend a thread.

src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,6 +1618,16 @@ public Task Continue(DebuggedThread thread)
16181618
return Execute(thread);
16191619
}
16201620

1621+
public async Task Jump(string filename, int line)
1622+
{
1623+
await MICommandFactory.ExecJump(filename, line);
1624+
}
1625+
1626+
public async Task Jump(ulong address)
1627+
{
1628+
await MICommandFactory.ExecJump(address);
1629+
}
1630+
16211631
public async Task Step(int threadId, enum_STEPKIND kind, enum_STEPUNIT unit)
16221632
{
16231633
this.VerifyNotDebuggingCoreDump();

src/OpenDebugAD7/AD7DebugSession.cs

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
namespace OpenDebugAD7
2929
{
30-
internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2
30+
internal sealed class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEventCallback2
3131
{
3232
// This is a general purpose lock. Don't hold it across long operations.
3333
private readonly object m_lock = new object();
@@ -42,6 +42,8 @@ internal class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDebugEven
4242

4343
private readonly DebugEventLogger m_logger;
4444
private readonly Dictionary<string, Dictionary<int, IDebugPendingBreakpoint2>> m_breakpoints;
45+
private readonly List<IDebugCodeContext2> m_gotoCodeContexts = new List<IDebugCodeContext2>();
46+
4547
private Dictionary<string, IDebugPendingBreakpoint2> m_functionBreakpoints;
4648
private readonly Dictionary<int, ThreadFrameEnumInfo> m_threadFrameEnumInfos = new Dictionary<int, ThreadFrameEnumInfo>();
4749
private readonly HandleCollection<IDebugStackFrame2> m_frameHandles;
@@ -277,6 +279,7 @@ public void BeforeContinue()
277279
m_variableManager.Reset();
278280
m_frameHandles.Reset();
279281
m_threadFrameEnumInfos.Clear();
282+
m_gotoCodeContexts.Clear();
280283
}
281284
}
282285

@@ -620,7 +623,8 @@ protected override void HandleInitializeRequestAsync(IRequestResponder<Initializ
620623
ExceptionBreakpointFilters = m_engineConfiguration.ExceptionSettings.ExceptionBreakpointFilters.Select(item => new ExceptionBreakpointsFilter() { Default = item.@default, Filter = item.filter, Label = item.label }).ToList(),
621624
SupportsClipboardContext = m_engineConfiguration.ClipboardContext,
622625
SupportsLogPoints = true,
623-
SupportsReadMemoryRequest = true
626+
SupportsReadMemoryRequest = true,
627+
SupportsGotoTargetsRequest = true,
624628
};
625629

626630
responder.SetResponse(initializeResponse);
@@ -1193,6 +1197,87 @@ protected override void HandlePauseRequestAsync(IRequestResponder<PauseArguments
11931197
m_program.CauseBreak();
11941198
responder.SetResponse(new PauseResponse());
11951199
}
1200+
1201+
protected override void HandleGotoRequestAsync(IRequestResponder<GotoArguments> responder)
1202+
{
1203+
var response = new GotoResponse();
1204+
if (!m_isStopped)
1205+
{
1206+
responder.SetResponse(response);
1207+
return;
1208+
}
1209+
1210+
var gotoTarget = m_gotoCodeContexts[responder.Arguments.TargetId];
1211+
IDebugThread2 thread = null;
1212+
lock (m_threads)
1213+
{
1214+
if (!m_threads.TryGetValue(responder.Arguments.ThreadId, out thread))
1215+
throw new AD7Exception("Could not find thread!");
1216+
}
1217+
BeforeContinue();
1218+
var builder = new ErrorBuilder(() => AD7Resources.Error_UnableToSetNextStatement);
1219+
try
1220+
{
1221+
builder.CheckHR(thread.SetNextStatement(null, gotoTarget));
1222+
}
1223+
catch (AD7Exception e)
1224+
{
1225+
m_isStopped = true;
1226+
responder.SetError(new ProtocolException(e.Message));
1227+
}
1228+
1229+
responder.SetResponse(response);
1230+
}
1231+
1232+
protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTargetsArguments, GotoTargetsResponse> responder)
1233+
{
1234+
var response = new GotoTargetsResponse();
1235+
1236+
var source = responder.Arguments.Source;
1237+
// TODO: handle this for disassembly debugging
1238+
if (source.Path == null)
1239+
{
1240+
responder.SetResponse(response);
1241+
return;
1242+
}
1243+
1244+
try
1245+
{
1246+
string convertedPath = m_pathConverter.ConvertClientPathToDebugger(source.Path);
1247+
int line = m_pathConverter.ConvertClientLineToDebugger(responder.Arguments.Line);
1248+
var docPos = new AD7DocumentPosition(m_sessionConfig, convertedPath, line);
1249+
1250+
var targets = new List<GotoTarget>();
1251+
1252+
IEnumDebugCodeContexts2 codeContextsEnum;
1253+
if (m_program.EnumCodeContexts(docPos, out codeContextsEnum) == HRConstants.S_OK)
1254+
{
1255+
var codeContexts = new IDebugCodeContext2[1];
1256+
uint nProps = 0;
1257+
while (codeContextsEnum.Next(1, codeContexts, ref nProps) == HRConstants.S_OK)
1258+
{
1259+
var codeContext = codeContexts[0];
1260+
string contextName;
1261+
codeContext.GetName(out contextName);
1262+
m_gotoCodeContexts.Add(codeContext);
1263+
targets.Add(new GotoTarget(m_gotoCodeContexts.Count - 1, contextName, responder.Arguments.Line)); // TODO: get the real line
1264+
}
1265+
}
1266+
1267+
response.Targets = targets;
1268+
}
1269+
catch (Exception e)
1270+
{
1271+
e = Utilities.GetInnerMost(e);
1272+
if (Utilities.IsCorruptingException(e))
1273+
Utilities.ReportException(e);
1274+
1275+
responder.SetError(new ProtocolException(e.Message));
1276+
return;
1277+
}
1278+
1279+
responder.SetResponse(response);
1280+
}
11961281

11971282
protected override void HandleStackTraceRequestAsync(IRequestResponder<StackTraceArguments, StackTraceResponse> responder)
11981283
{

0 commit comments

Comments
 (0)