Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit b9b102b

Browse files
author
Mike McLaughlin
committed
Fix sos clrstack unwinding for the special HelperMethodFrame.
Add and implement new ICorDebugDataTarget4 unwind interface using lldb stack unwinder ABIs. The implementation does a linear search of the native frames for the stack pointer provided. It doesn't happen often so the performance is fine. Stub out the DBI's ICorDebugDataTarget4 (in ShimDataTarget::VirtualUnwind) for now. Since PAL_VirtualUnwindOutOfProc is disabled it makes sense to just return E_NOTIMPL. Fix bpmd command so it doesn't stop in lldb when it isn't a CLRN exception (continues).
1 parent 4c3e266 commit b9b102b

File tree

24 files changed

+204
-92
lines changed

24 files changed

+204
-92
lines changed

src/ToolBox/SOS/Strike/datatarget.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,14 @@ DataTarget::Request(
196196
}
197197

198198
HRESULT STDMETHODCALLTYPE
199-
DataTarget::GetPid(
200-
/* [out] */ DWORD *pdwProcessId)
199+
DataTarget::VirtualUnwind(
200+
/* [in] */ DWORD threadId,
201+
/* [in] */ ULONG32 contextSize,
202+
/* [in, out, size_is(contextSize)] */ PBYTE context)
201203
{
202-
return g_ExtSystem->GetCurrentProcessId(pdwProcessId);
204+
if (g_ExtClient == NULL)
205+
{
206+
return E_UNEXPECTED;
207+
}
208+
return g_ExtClient->VirtualUnwind(threadId, contextSize, context);
203209
}

src/ToolBox/SOS/Strike/datatarget.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class DataTarget : public ICLRDataTarget, ICorDebugDataTarget4
8585

8686
// ICorDebugDataTarget4
8787

88-
virtual HRESULT STDMETHODCALLTYPE GetPid(
89-
/* [out] */ DWORD *pdwProcessId);
88+
virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(
89+
/* [in] */ DWORD threadId,
90+
/* [in] */ ULONG32 contextSize,
91+
/* [in, out, size_is(contextSize)] */ PBYTE context);
9092
};

src/ToolBox/SOS/Strike/strike.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6892,8 +6892,13 @@ HRESULT HandleCLRNotificationEvent()
68926892

68936893
if (!CheckCLRNotificationEvent(&dle))
68946894
{
6895+
#ifndef FEATURE_PAL
68956896
ExtOut("Expecting first chance CLRN exception\n");
68966897
return E_FAIL;
6898+
#else
6899+
g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "process continue", 0);
6900+
return S_OK;
6901+
#endif
68976902
}
68986903

68996904
// Notification only needs to live for the lifetime of the call below, so it's a non-static

src/ToolBox/SOS/lldbplugin/debugclient.cpp

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <cstdlib>
88
#include "sosplugin.h"
99
#include <string.h>
10-
#include <dbgtargetcontext.h>
1110
#include <string>
1211

1312
ULONG g_currentThreadIndex = -1;
@@ -708,8 +707,8 @@ DebugClient::GetModuleDirectory(
708707
// Internal function
709708
ULONG64
710709
DebugClient::GetModuleBase(
711-
lldb::SBTarget target,
712-
lldb::SBModule module)
710+
/* const */ lldb::SBTarget& target,
711+
/* const */ lldb::SBModule& module)
713712
{
714713
// Find the first section with an valid base address
715714
int numSections = module.GetNumSections();
@@ -922,6 +921,19 @@ DebugClient::GetThreadContextById(
922921
dtcontext = (DT_CONTEXT*)context;
923922
dtcontext->ContextFlags = contextFlags;
924923

924+
GetContextFromFrame(frame, dtcontext);
925+
hr = S_OK;
926+
927+
exit:
928+
return hr;
929+
}
930+
931+
// Internal function
932+
void
933+
DebugClient::GetContextFromFrame(
934+
/* const */ lldb::SBFrame& frame,
935+
DT_CONTEXT *dtcontext)
936+
{
925937
#ifdef DBG_TARGET_AMD64
926938
dtcontext->Rip = frame.GetPC();
927939
dtcontext->Rsp = frame.GetSP();
@@ -969,29 +981,19 @@ DebugClient::GetThreadContextById(
969981
dtcontext->R11 = GetRegister(frame, "r11");
970982
dtcontext->R12 = GetRegister(frame, "r12");
971983
#endif
972-
973-
hr = S_OK;
974-
975-
exit:
976-
return hr;
977984
}
978985

979986
// Internal function
980987
DWORD_PTR
981-
DebugClient::GetRegister(lldb::SBFrame frame, const char *name)
988+
DebugClient::GetRegister(
989+
/* const */ lldb::SBFrame& frame,
990+
const char *name)
982991
{
983992
lldb::SBValue regValue = frame.FindRegister(name);
984993

985994
lldb::SBError error;
986995
DWORD_PTR result = regValue.GetValueAsUnsigned(error);
987996

988-
#ifdef _DEBUG
989-
if (!regValue.IsValid() || error.Fail())
990-
{
991-
Output(DEBUG_OUTPUT_ERROR, "Invalid register name '%s'\n", name);
992-
}
993-
#endif
994-
995997
return result;
996998
}
997999

@@ -1115,7 +1117,7 @@ DebugClient::GetExpression(
11151117
// Internal function
11161118
DWORD_PTR
11171119
DebugClient::GetExpression(
1118-
lldb::SBFrame frame,
1120+
/* const */ lldb::SBFrame& frame,
11191121
lldb::SBError& error,
11201122
PCSTR exp)
11211123
{
@@ -1130,6 +1132,70 @@ DebugClient::GetExpression(
11301132
return result;
11311133
}
11321134

1135+
HRESULT
1136+
DebugClient::VirtualUnwind(
1137+
DWORD threadID,
1138+
ULONG32 contextSize,
1139+
PBYTE context)
1140+
{
1141+
lldb::SBProcess process;
1142+
lldb::SBThread thread;
1143+
1144+
if (context == NULL || contextSize < sizeof(DT_CONTEXT))
1145+
{
1146+
return E_FAIL;
1147+
}
1148+
1149+
process = GetCurrentProcess();
1150+
if (!process.IsValid())
1151+
{
1152+
return E_FAIL;
1153+
}
1154+
1155+
thread = process.GetThreadByID(threadID);
1156+
if (!thread.IsValid())
1157+
{
1158+
return E_FAIL;
1159+
}
1160+
1161+
DT_CONTEXT *dtcontext = (DT_CONTEXT*)context;
1162+
lldb::SBFrame frameFound;
1163+
1164+
#ifdef DBG_TARGET_AMD64
1165+
DWORD64 spToFind = dtcontext->Rsp;
1166+
#elif DBG_TARGET_ARM
1167+
DWORD spToFind = dtcontext->Sp;
1168+
#endif
1169+
1170+
int numFrames = thread.GetNumFrames();
1171+
for (int i = 0; i < numFrames; i++)
1172+
{
1173+
lldb::SBFrame frame = thread.GetFrameAtIndex(i);
1174+
if (!frame.IsValid())
1175+
{
1176+
break;
1177+
}
1178+
1179+
lldb::addr_t sp = frame.GetSP();
1180+
1181+
if (sp == spToFind && (i + 1) < numFrames)
1182+
{
1183+
// Get next frame after finding the match
1184+
frameFound = thread.GetFrameAtIndex(i + 1);
1185+
break;
1186+
}
1187+
}
1188+
1189+
if (!frameFound.IsValid())
1190+
{
1191+
return E_FAIL;
1192+
}
1193+
1194+
GetContextFromFrame(frameFound, dtcontext);
1195+
1196+
return S_OK;
1197+
}
1198+
11331199
//----------------------------------------------------------------------------
11341200
// Helper functions
11351201
//----------------------------------------------------------------------------

src/ToolBox/SOS/lldbplugin/debugclient.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ class DebugClient : public IDebugClient
1313
lldb::SBProcess GetCurrentProcess();
1414
lldb::SBThread GetCurrentThread();
1515
lldb::SBFrame GetCurrentFrame();
16-
ULONG64 GetModuleBase(lldb::SBTarget target, lldb::SBModule module);
17-
DWORD_PTR GetExpression(lldb::SBFrame frame, lldb::SBError& error, PCSTR exp);
18-
DWORD_PTR GetRegister(lldb::SBFrame frame, const char *name);
16+
ULONG64 GetModuleBase(lldb::SBTarget& target, lldb::SBModule& module);
17+
DWORD_PTR GetExpression(lldb::SBFrame& frame, lldb::SBError& error, PCSTR exp);
18+
void GetContextFromFrame(lldb::SBFrame& frame, DT_CONTEXT *dtcontext);
19+
DWORD_PTR GetRegister(lldb::SBFrame& frame, const char *name);
1920

2021
public:
2122
DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject);
@@ -192,4 +193,9 @@ class DebugClient : public IDebugClient
192193

193194
DWORD_PTR GetExpression(
194195
PCSTR exp);
196+
197+
HRESULT VirtualUnwind(
198+
DWORD threadID,
199+
ULONG32 contextSize,
200+
PBYTE context);
195201
};

src/ToolBox/SOS/lldbplugin/inc/dbgeng.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,11 @@ class IDebugClient : IDebugControl2, IDebugDataSpaces, IDebugSymbols, IDebugSyst
457457
// Evaluates a lldb expression into a value.
458458
virtual DWORD_PTR GetExpression(
459459
/* [in] */ PCSTR exp) = 0;
460+
461+
virtual HRESULT VirtualUnwind(
462+
/* [in] */ DWORD threadID,
463+
/* [in] */ ULONG32 contextSize,
464+
/* [in, out, size_is(contextSize)] */ PBYTE context) = 0;
460465
};
461466

462467
typedef class IDebugClient* PDEBUG_CLIENT;

src/ToolBox/SOS/lldbplugin/sosplugin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "mstypes.h"
88
#define DEFINE_EXCEPTION_RECORD
99
#include <dbgeng.h>
10+
#include <dbgtargetcontext.h>
1011
#include "debugclient.h"
1112

1213
typedef HRESULT (*CommandFunc)(PDEBUG_CLIENT client, const char *args);

src/debug/daccess/dacfn.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,19 +219,25 @@ DacWriteAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx)
219219
}
220220

221221
HRESULT
222-
DacGetPid(DWORD *pid)
222+
DacVirtualUnwind(DWORD threadId, CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
223223
{
224224
if (!g_dacImpl)
225225
{
226226
DacError(E_UNEXPECTED);
227227
UNREACHABLE();
228228
}
229229

230+
// The DAC code doesn't use these context pointers but zero them out to be safe.
231+
if (contextPointers != NULL)
232+
{
233+
memset(contextPointers, 0, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
234+
}
235+
230236
ReleaseHolder<ICorDebugDataTarget4> dt;
231237
HRESULT hr = g_dacImpl->m_pTarget->QueryInterface(IID_ICorDebugDataTarget4, (void **)&dt);
232238
if (SUCCEEDED(hr))
233239
{
234-
hr = dt->GetPid(pid);
240+
hr = dt->VirtualUnwind(threadId, sizeof(CONTEXT), (BYTE*)context);
235241
}
236242

237243
return hr;

src/debug/di/shimdatatarget.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,22 +68,30 @@ ULONG STDMETHODCALLTYPE ShimDataTarget::Release()
6868
return ref;
6969
}
7070

71-
7271
//---------------------------------------------------------------------------------------
7372
//
7473
// Get the OS Process ID that this DataTarget is for.
7574
//
7675
// Return Value:
7776
// The OS PID of the process this data target is representing.
78-
HRESULT STDMETHODCALLTYPE ShimDataTarget::GetPid(DWORD *pdwProcessId)
77+
DWORD ShimDataTarget::GetPid()
7978
{
80-
if (pdwProcessId == NULL)
81-
{
82-
return E_INVALIDARG;
83-
}
79+
return m_processId;
80+
}
8481

85-
*pdwProcessId = m_processId;
86-
return S_OK;
82+
//---------------------------------------------------------------------------------------
83+
//
84+
// Unwind the stack to the next frame.
85+
//
86+
// Return Value:
87+
// context and contextPointers filled in with the next frame
88+
//
89+
HRESULT STDMETHODCALLTYPE ShimDataTarget::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
90+
{
91+
#ifndef FEATURE_PAL
92+
_ASSERTE(!"ShimDataTarget::VirtualUnwind NOT IMPLEMENTED");
93+
#endif
94+
return E_NOTIMPL;
8795
}
8896

8997
//---------------------------------------------------------------------------------------

src/debug/di/shimdatatarget.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4
3636
// is unavailable because it's running
3737
void SetError(HRESULT hr);
3838

39+
// Get the OS Process ID that this DataTarget is for.
40+
DWORD GetPid();
41+
3942
//
4043
// IUnknown.
4144
//
@@ -86,8 +89,8 @@ class ShimDataTarget : public ICorDebugMutableDataTarget, ICorDebugDataTarget4
8689
// ICorDebugDataTarget4
8790
//
8891

89-
// Get the OS Process ID that this DataTarget is for.
90-
virtual HRESULT STDMETHODCALLTYPE GetPid(DWORD *pdwProcessId);
92+
// Unwind to the next stack frame
93+
virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context);
9194

9295
protected:
9396
// Pid of the target process.

0 commit comments

Comments
 (0)