3 #include "../../GDBServerFoundation/HexHelpers.h"
4 #include <bzscore/path.h>
6 using namespace VBoxGDB;
7 using namespace BazisLib;
13 , m_BreakpointIDOfLastStopEvent(-1)
14 , m_LastBlockReadAddr(-1LL)
17 m_BufferAllocationSize = 1024 * 1024;
18 m_Socket.SetNoDelay(
true);
28 bool VBoxGDB::VBoxClient::RecvTillCommandPrompt()
30 const char debugPrompt[] =
"VBoxDbg>";
31 m_Buffer.SetLength(0);
32 size_t done = m_Socket.RecvToMarker(m_Buffer.PreAllocate(m_BufferAllocationSize,
false), m_BufferAllocationSize, debugPrompt,
sizeof(debugPrompt) - 1);
33 if (done == 0 || done == -1 || done < (
sizeof(debugPrompt) - 1))
35 m_Buffer.SetLength(done - (
sizeof(debugPrompt) - 1));
41 if (!RecvTillCommandPrompt())
43 std::vector<DynamicStringA> result;
45 #ifdef USE_REG_WORKAROUND_DLL
47 GetModuleFileName(GetModuleHandle(0), tsz, __countof(tsz));
49 DynamicStringA str =
"loadplugin ";
50 str += StringToANSIString(Path::GetDirectoryName(TempStrPointerWrapper(tsz))) +
"/regfix64.dll";
51 for (
size_t i = 0; i < str.length(); i++)
54 result = ExecuteCommand(str.c_str());
55 if (!IsSuccessfulReply(result))
57 ReportError(
"Cannot load regfix64.dll into VirtualBox. Debugging won't be possible.");
62 result = ExecuteCommand(
"cpu ffff");
63 for (
size_t i = 0; i < result.size(); i++)
65 const char szPattern[] =
"is out of range! Highest ID is ";
66 size_t idx = result[i].find(szPattern);
69 m_CPUCount = atoi(result[i].c_str() + idx +
sizeof(szPattern) - 1);
83 std::string str = pCommand;
86 m_Socket.Send(str.c_str(), str.length());
88 std::vector<DynamicStringA> result;
89 if (!RecvTillCommandPrompt())
92 for each(
const TempStringA &str
in m_Buffer.Split(
"\r\n"))
93 result.push_back(str);
100 printf(
"Error: %s\n", pErrorDescription);
105 m_Socket.Send(
"stop\n", 5);
108 static bool FindNextRegVal(
const DynamicStringA &str,
size_t &initial, TempStringA ®Name, TempStringA ®Val)
110 size_t idx = str.find(
'=', initial);
111 if (idx == -1 || !idx)
114 size_t regStart = 0, regEnd = idx;
117 regStart = str.rfind(
' ', regEnd - 1);
123 if (regEnd != regStart || !regStart)
126 regEnd = regStart - 1;
130 regName = str.substr(regStart, regEnd - regStart);
132 size_t end = str.find_first_not_of(
"0x123456789ABCDEFabcdef", idx + 1);
136 regVal = str.substr(idx + 1, end - idx - 1);
143 std::map<DynamicStringA, ULONGLONG> result;
144 std::vector<DynamicStringA> lines = ExecuteCommand(m_b64Bit ?
"rg64" :
"rg32");
145 for (
size_t i = 0; i < lines.size(); i++)
150 TempStringA regName(ConstStringA(
""));
151 TempStringA regVal(ConstStringA(
""));
155 result[regName] = GDBServerFoundation::HexHelpers::ParseHexString<ULONGLONG>(regVal);
164 DynamicStringA strCmd;
165 #ifdef USE_REG_WORKAROUND_DLL
166 const char *pRegCmd =
".r";
168 const char *pRegCmd =
"r";
172 strCmd.Format(
"%s %s 0x%08X", pRegCmd, pName, (
unsigned)value);
174 strCmd.Format(
"%s %s 0x%016I64x", pRegCmd, pName, value);
176 std::vector<DynamicStringA> result = ExecuteCommand(strCmd.c_str());
177 return IsSuccessfulReply(result);
180 static bool StartsWith(
const TempStringA &str,
const char *pStr)
182 size_t len = strlen(pStr);
183 if (str.length() < len)
185 return !memcmp(str.GetConstBuffer(), pStr, len);
190 static const char szEvent[] =
"dbgf event:";
191 static const char szWarning[] =
"warning: The VM is already halted...";
192 static const char szBreakpoint[] =
"Breakpoint ";
196 if (!RecvTillCommandPrompt())
199 int idx = m_Buffer.find_first_not_of(
" \r\n\t");
203 TempStringA &str = m_Buffer.substr(idx);
206 TempStringA evt = str.substr(
sizeof(szEvent));
209 m_BreakpointIDOfLastStopEvent = atoi(evt.GetConstBuffer() +
sizeof(szBreakpoint) - 1);
210 AdjustPCAfterBreakpoint(m_BreakpointIDOfLastStopEvent);
213 m_BreakpointIDOfLastStopEvent = -1;
225 m_Socket.Send(
"exit\n", 5);
226 RecvTillCommandPrompt();
232 for (
size_t i = 0; i < reply.size(); i++)
234 if (reply[i].find(
"error:") != -1)
237 ReportError(reply[i].c_str());
244 bool VBoxGDB::VBoxClient::ReadMemoryBlockAligned( ULONGLONG address, BazisLib::BasicBuffer &buffer )
248 ReportError(
"Error: trying to read from an unaligned address");
252 DynamicStringA strCmd;
254 strCmd.Format(
"dd 0x%08X", (
unsigned)address);
256 strCmd.Format(
"dd 0x%016I64x", address);
258 std::vector<DynamicStringA> result = ExecuteCommand(strCmd.c_str());
260 ULONGLONG expectedAddr = address;
261 for (
size_t i = 0; i < result.size(); i++)
263 const DynamicStringA &line = result[i];
264 int idx = line.find(
':');
265 if (idx == -1 || !idx)
267 size_t lineStart = line.find_first_not_of(
" \t");
270 if (line[lineStart] !=
'%')
273 ULONGLONG thisAddr = GDBServerFoundation::HexHelpers::ParseHexString<ULONGLONG>(line.substr(lineStart + 1, idx - lineStart - 1));
274 if (thisAddr != expectedAddr)
277 size_t start = idx + 1;
280 size_t numStart = line.find_first_not_of(
' ', start);
283 size_t numEnd = line.find(
' ', numStart);
285 numEnd = line.length();
287 unsigned num = GDBServerFoundation::HexHelpers::ParseHexString<unsigned>(line.substr(numStart, numEnd - numStart));
288 C_ASSERT(
sizeof(num) == 4);
289 buffer.append(&num, 4, 4096);
301 m_LastBlockReadAddr = -1LL;
302 const char *p = (
const char *)pData;
303 size_t remaining = length;
304 DynamicStringA strVal, strCmd;
313 strVal.Format(
"%016I64x", *((ULONGLONG *)p));
316 else if (remaining >= 4)
319 strVal.Format(
"%08x", *((
unsigned *)p));
322 else if (remaining >= 2)
325 strVal.Format(
"%04x", *((
unsigned short *)p));
331 strVal.Format(
"%02x", *((
unsigned char *)p));
336 strCmd.Format(
"e%c 0x%016I64x %s", mode, address, strVal.c_str());
338 strCmd.Format(
"e%c 0x%08x %s", mode, (
unsigned)address, strVal.c_str());
340 std::vector<DynamicStringA> result = ExecuteCommand(strCmd.c_str());
341 if (!IsSuccessfulReply(result))
353 size_t requested = *pLength, done = 0;
355 char *p = (
char *)pData;
357 if (allowCaching && m_LastBlockReadAddr != -1LL && (address >= m_LastBlockReadAddr) && (address < (m_LastBlockReadAddr + m_LastBlockReadBuffer.GetSize())))
359 size_t offsetInBuffer = (size_t)(address - m_LastBlockReadAddr);
360 size_t available = m_LastBlockReadBuffer.GetSize() - offsetInBuffer;
362 size_t todo = min(requested, available);
363 memcpy(p, m_LastBlockReadBuffer.GetData(offsetInBuffer), todo);
369 unsigned off = address & 3;
372 while (done < requested)
374 if (!ReadMemoryBlockAligned(address, m_LastBlockReadBuffer))
376 m_LastBlockReadAddr = address;
377 if (!m_LastBlockReadBuffer.GetSize())
379 ASSERT(!(m_LastBlockReadBuffer.GetSize() & 3));
381 size_t todo = min(requested - done, m_LastBlockReadBuffer.GetSize() - off);
382 memcpy(p, m_LastBlockReadBuffer.GetData(off), todo);
395 if (!IsSuccessfulReply(ExecuteCommand(
"t")))
397 return WaitForStop();
402 if (!IsSuccessfulReply(ExecuteCommand(
"g")))
404 return WaitForStop();
409 std::vector<DynamicStringA> result = ExecuteCommand(DynamicStringA::sFormat(
"bp 0x%I64x", addr).c_str());
410 const char szText[] =
"Set breakpoint ";
411 for (
size_t i = 0; i < result.size(); i++)
413 off_t idx = result[i].find(szText);
416 int bp = atoi(result[i].c_str() + idx +
sizeof(szText) - 1);
419 m_BreakpointMap[bp] = addr;
427 std::vector<DynamicStringA> result = ExecuteCommand(DynamicStringA::sFormat(
"bc %x", idx).c_str());
428 if (!IsSuccessfulReply(result))
430 BreakpointAddressMap::iterator it = m_BreakpointMap.find(idx);
431 if (it != m_BreakpointMap.end())
433 m_BreakpointMap.erase(it);
438 void VBoxGDB::VBoxClient::AdjustPCAfterBreakpoint(
int breakpointNumber )
440 ULONGLONG val = GetCurrentPC();
441 BreakpointAddressMap::iterator it = m_BreakpointMap.find(breakpointNumber);
442 if (it == m_BreakpointMap.end())
444 if (val == (it->second + 1))
452 const char *pRegName = m_b64Bit ?
"rip" :
"eip";
453 WriteRegister(pRegName, it->second);
459 std::vector<DynamicStringA> result = ExecuteCommand(DynamicStringA::sFormat(
"r %s", pName).c_str());
460 for (
size_t i = 0; i < result.size(); i++)
462 TempStringA regName(ConstStringA(
""));
463 TempStringA regVal(ConstStringA(
""));
468 *pValue = GDBServerFoundation::HexHelpers::ParseHexString<ULONGLONG>(regVal);
475 ULONGLONG VBoxGDB::VBoxClient::GetCurrentPC()
477 const char *pRegName = m_b64Bit ?
"rip" :
"eip";
479 if (!ReadRegister(pRegName, &val))