Patch for fixing the handling of hardware breakpoints.

Differential Revision: http://llvm-reviews.chandlerc.com/D2826

llvm-svn: 202028
This commit is contained in:
Deepak Panickal 2014-02-24 11:50:46 +00:00
parent 0032b4d519
commit b98a2bb7a8
2 changed files with 100 additions and 62 deletions

View File

@ -2675,15 +2675,10 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto
uint8_t
GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length)
{
switch (type)
{
case eBreakpointSoftware: if (!m_supports_z0) return UINT8_MAX; break;
case eBreakpointHardware: if (!m_supports_z1) return UINT8_MAX; break;
case eWatchpointWrite: if (!m_supports_z2) return UINT8_MAX; break;
case eWatchpointRead: if (!m_supports_z3) return UINT8_MAX; break;
case eWatchpointReadWrite: if (!m_supports_z4) return UINT8_MAX; break;
}
// Check if the stub is known not to support this breakpoint type
if (!SupportsGDBStoppointPacket(type))
return UINT8_MAX;
// Construct the breakpoint packet
char packet[64];
const int packet_len = ::snprintf (packet,
sizeof(packet),
@ -2692,28 +2687,35 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type,
type,
addr,
length);
// Check we havent overwritten the end of the packet buffer
assert (packet_len + 1 < (int)sizeof(packet));
StringExtractorGDBRemote response;
// Try to send the breakpoint packet, and check that it was correctly sent
if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success)
{
// Receive and OK packet when the breakpoint successfully placed
if (response.IsOKResponse())
return 0;
else if (response.IsErrorResponse())
// Error while setting breakpoint, send back specific error
if (response.IsErrorResponse())
return response.GetError();
}
else
{
switch (type)
// Empty packet informs us that breakpoint is not supported
if (response.IsUnsupportedResponse())
{
// Disable this breakpoint type since it is unsupported
switch (type)
{
case eBreakpointSoftware: m_supports_z0 = false; break;
case eBreakpointHardware: m_supports_z1 = false; break;
case eWatchpointWrite: m_supports_z2 = false; break;
case eWatchpointRead: m_supports_z3 = false; break;
case eWatchpointReadWrite: m_supports_z4 = false; break;
}
}
}
// Signal generic faliure
return UINT8_MAX;
}

View File

@ -2310,70 +2310,106 @@ Error
ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site)
{
Error error;
assert (bp_site != NULL);
assert(bp_site != NULL);
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
// Get logging info
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
user_id_t site_id = bp_site->GetID();
const addr_t addr = bp_site->GetLoadAddress();
if (log)
log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr);
// Get the breakpoint address
const addr_t addr = bp_site->GetLoadAddress();
// Log that a breakpoint was requested
if (log)
log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr);
// Breakpoint already exists and is enabled
if (bp_site->IsEnabled())
{
if (log)
log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
return error;
}
else
{
const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
if (bp_site->HardwareRequired())
// Get the software breakpoint trap opcode size
const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
// SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type
// is supported by the remote stub. These are set to true by default, and later set to false
// only after we receive an unimplemented response when sending a breakpoint packet. This means
// initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will
// attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which
// indicates if the user specifically asked for hardware breakpoints. If true then we will
// skip over software breakpoints.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired()))
{
// Try to send off a software breakpoint packet ($Z0)
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0)
{
// Try and set hardware breakpoint, and if that fails, fall through
// and set a software breakpoint?
if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware))
{
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0)
{
bp_site->SetEnabled(true);
bp_site->SetType (BreakpointSite::eHardware);
}
else
{
error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)");
}
}
else
{
error.SetErrorString("hardware breakpoints are not supported");
}
// The breakpoint was placed successfully
bp_site->SetEnabled(true);
bp_site->SetType(BreakpointSite::eExternal);
return error;
}
else if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
// SendGDBStoppointTypePacket() will return an error if it was unable to set this
// breakpoint. We need to differentiate between a error specific to placing this breakpoint
// or if we have learned that this breakpoint type is unsupported. To do this, we
// must test the support boolean for this breakpoint type to see if it now indicates that
// this breakpoint type is unsupported. If they are still supported then we should return
// with the error code. If they are now unsupported, then we would like to fall through
// and try another form of breakpoint.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
return error;
// We reach here when software breakpoints have been found to be unsupported. For future
// calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is
// known not to be supported.
if (log)
log->Printf("Software breakpoints are unsupported");
// So we will fall through and try a hardware breakpoint
}
// The process of setting a hardware breakpoint is much the same as above. We check the
// supported boolean for this breakpoint type, and if it is thought to be supported then we
// will try to set this breakpoint with a hardware breakpoint.
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware))
{
// Try to send off a hardware breakpoint packet ($Z1)
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0)
{
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0)
{
bp_site->SetEnabled(true);
bp_site->SetType (BreakpointSite::eExternal);
return error;
}
// The breakpoint was placed successfully
bp_site->SetEnabled(true);
bp_site->SetType(BreakpointSite::eHardware);
return error;
}
return EnableSoftwareBreakpoint (bp_site);
// Check if the error was something other then an unsupported breakpoint type
if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware))
{
// Unable to set this hardware breakpoint
error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)");
return error;
}
// We will reach here when the stub gives an unsported response to a hardware breakpoint
if (log)
log->Printf("Hardware breakpoints are unsupported");
// Finally we will falling through to a #trap style breakpoint
}
if (log)
// Don't fall through when hardware breakpoints were specifically requested
if (bp_site->HardwareRequired())
{
const char *err_string = error.AsCString();
log->Printf ("ProcessGDBRemote::EnableBreakpointSite () error for breakpoint at 0x%8.8" PRIx64 ": %s",
bp_site->GetLoadAddress(),
err_string ? err_string : "NULL");
error.SetErrorString("hardware breakpoints are not supported");
return error;
}
// We shouldn't reach here on a successful breakpoint enable...
if (error.Success())
error.SetErrorToGenericError();
return error;
// As a last resort we want to place a manual breakpoint. An instruction
// is placed into the process memory using memory write packets.
return EnableSoftwareBreakpoint(bp_site);
}
Error
@ -2399,7 +2435,7 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
break;
case BreakpointSite::eHardware:
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size))
error.SetErrorToGenericError();
break;