Commit 19bc0ea2 authored by Milad Farazmand's avatar Milad Farazmand Committed by Commit Bot

PPC/s390: [arm32] Fix breakpoints in simulator/debugger

Port e920b2e3

Original Commit Message:

    - Debugger stepping assumes that the pc points to the instruction
      that should get executed next, so we need to increment it when
      we hit a stop or a bkpt instruction or else we'll end up in an
      infinite loop.
    - The "break" and the "stop unstop" command write into code space, so
      they need to temporarily make code space writable or else they
      just crash. (Note that this doesn't work for embedded builtins.)

R=neis@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
LOG=N

Change-Id: I1a9507f621c83dd94f2de230f7c75bc1fee95dd0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2031204Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Milad Farazmand <miladfar@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#66057}
parent 0ca45a20
......@@ -19,6 +19,7 @@
#include "src/diagnostics/disasm.h"
#include "src/execution/ppc/frame-constants-ppc.h"
#include "src/heap/combined-heap.h"
#include "src/heap/heap-inl.h" // For CodeSpaceMemoryModificationScope.
#include "src/objects/objects-inl.h"
#include "src/runtime/runtime-utils.h"
#include "src/utils/ostreams.h"
......@@ -41,8 +42,6 @@ DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
class PPCDebugger {
public:
explicit PPCDebugger(Simulator* sim) : sim_(sim) {}
void Stop(Instruction* instr);
void Debug();
private:
......@@ -57,34 +56,20 @@ class PPCDebugger {
bool GetValue(const char* desc, intptr_t* value);
bool GetFPDoubleValue(const char* desc, double* value);
// Set or delete a breakpoint. Returns true if successful.
// Set or delete breakpoint (there can be only one).
bool SetBreakpoint(Instruction* break_pc);
bool DeleteBreakpoint(Instruction* break_pc);
void DeleteBreakpoint();
// Undo and redo all breakpoints. This is needed to bracket disassembly and
// execution to skip past breakpoints when run from the debugger.
void UndoBreakpoints();
void RedoBreakpoints();
// Undo and redo the breakpoint. This is needed to bracket disassembly and
// execution to skip past the breakpoint when run from the debugger.
void UndoBreakpoint();
void RedoBreakpoint();
};
void PPCDebugger::Stop(Instruction* instr) {
// Get the stop code.
// use of kStopCodeMask not right on PowerPC
uint32_t code = instr->SvcValue() & kStopCodeMask;
// Retrieve the encoded address, which comes just after this stop.
char* msg = *reinterpret_cast<char**>(sim_->get_pc() + kInstrSize);
// Update this stop description.
if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
sim_->watched_stops_[code].desc = msg;
}
// Print the stop message and code if it is not the default code.
if (code != kMaxStopCode) {
PrintF("Simulator hit stop %u: %s\n", code, msg);
} else {
PrintF("Simulator hit %s\n", msg);
}
sim_->set_pc(sim_->get_pc() + kInstrSize + kPointerSize);
Debug();
void Simulator::DebugAtNextPC() {
PrintF("Starting debugger on the next instruction:\n");
set_pc(get_pc() + kInstrSize);
PPCDebugger(this).Debug();
}
intptr_t PPCDebugger::GetRegisterValue(int regnum) {
......@@ -139,25 +124,33 @@ bool PPCDebugger::SetBreakpoint(Instruction* break_pc) {
return true;
}
bool PPCDebugger::DeleteBreakpoint(Instruction* break_pc) {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
namespace {
// This function is dangerous, but it's only available in non-production
// (simulator) builds.
void SetInstructionBitsInCodeSpace(Instruction* instr, Instr value,
Heap* heap) {
CodeSpaceMemoryModificationScope scope(heap);
instr->SetInstructionBits(value);
}
} // namespace
void PPCDebugger::DeleteBreakpoint() {
UndoBreakpoint();
sim_->break_pc_ = nullptr;
sim_->break_instr_ = 0;
return true;
}
void PPCDebugger::UndoBreakpoints() {
void PPCDebugger::UndoBreakpoint() {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
SetInstructionBitsInCodeSpace(sim_->break_pc_, sim_->break_instr_,
sim_->isolate_->heap());
}
}
void PPCDebugger::RedoBreakpoints() {
void PPCDebugger::RedoBreakpoint() {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
SetInstructionBitsInCodeSpace(sim_->break_pc_, kBreakpointInstr,
sim_->isolate_->heap());
}
}
......@@ -181,9 +174,9 @@ void PPCDebugger::Debug() {
arg1[ARG_SIZE] = 0;
arg2[ARG_SIZE] = 0;
// Undo all set breakpoints while running in the debugger shell. This will
// make them invisible to all commands.
UndoBreakpoints();
// Unset breakpoint while running in the debugger shell, making it invisible
// to all commands.
UndoBreakpoint();
// Disable tracing while simulating
bool trace = ::v8::internal::FLAG_trace_sim;
::v8::internal::FLAG_trace_sim = false;
......@@ -471,9 +464,7 @@ void PPCDebugger::Debug() {
PrintF("break <address>\n");
}
} else if (strcmp(cmd, "del") == 0) {
if (!DeleteBreakpoint(nullptr)) {
PrintF("deleting breakpoint failed\n");
}
DeleteBreakpoint();
} else if (strcmp(cmd, "cr") == 0) {
PrintF("Condition reg: %08x\n", sim_->condition_reg_);
} else if (strcmp(cmd, "lr") == 0) {
......@@ -493,7 +484,8 @@ void PPCDebugger::Debug() {
if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
// Remove the current stop.
if (sim_->isStopInstruction(stop_instr)) {
stop_instr->SetInstructionBits(kNopInstr);
SetInstructionBitsInCodeSpace(stop_instr, kNopInstr,
sim_->isolate_->heap());
msg_address->SetInstructionBits(kNopInstr);
} else {
PrintF("Not at debugger stop.\n");
......@@ -613,9 +605,9 @@ void PPCDebugger::Debug() {
}
}
// Add all the breakpoints back to stop execution and enter the debugger
// shell when hit.
RedoBreakpoints();
// Reinstall breakpoint to stop execution and enter the debugger shell when
// hit.
RedoBreakpoint();
// Restore tracing
::v8::internal::FLAG_trace_sim = trace;
......@@ -1210,13 +1202,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
set_pc(saved_lr);
break;
}
case kBreakpoint: {
PPCDebugger dbg(this);
dbg.Debug();
case kBreakpoint:
PPCDebugger(this).Debug();
break;
}
// stop uses all codes greater than 1 << 23.
default: {
default:
if (svc >= (1 << 23)) {
uint32_t code = svc & kStopCodeMask;
if (isWatchedStop(code)) {
......@@ -1225,17 +1215,19 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// Stop if it is enabled, otherwise go on jumping over the stop
// and the message address.
if (isEnabledStop(code)) {
PPCDebugger dbg(this);
dbg.Stop(instr);
if (code != kMaxStopCode) {
PrintF("Simulator hit stop %u. ", code);
} else {
PrintF("Simulator hit stop. ");
}
DebugAtNextPC();
} else {
set_pc(get_pc() + kInstrSize + kPointerSize);
}
} else {
// This is not a valid svc code.
UNREACHABLE();
break;
}
}
}
}
......
......@@ -238,6 +238,7 @@ class Simulator : public SimulatorBase {
void HandleRList(Instruction* instr, bool load);
void HandleVList(Instruction* inst);
void SoftwareInterrupt(Instruction* instr);
void DebugAtNextPC();
// Stop helper functions.
inline bool isStopInstruction(Instruction* instr);
......
......@@ -19,6 +19,7 @@
#include "src/codegen/s390/constants-s390.h"
#include "src/diagnostics/disasm.h"
#include "src/heap/combined-heap.h"
#include "src/heap/heap-inl.h" // For CodeSpaceMemoryModificationScope.
#include "src/objects/objects-inl.h"
#include "src/runtime/runtime-utils.h"
#include "src/utils/ostreams.h"
......@@ -39,8 +40,6 @@ const Simulator::fpr_t Simulator::fp_zero;
class S390Debugger {
public:
explicit S390Debugger(Simulator* sim) : sim_(sim) {}
void Stop(Instruction* instr);
void Debug();
private:
......@@ -61,34 +60,20 @@ class S390Debugger {
bool GetValue(const char* desc, intptr_t* value);
bool GetFPDoubleValue(const char* desc, double* value);
// Set or delete a breakpoint. Returns true if successful.
bool SetBreakpoint(Instruction* break_pc);
bool DeleteBreakpoint(Instruction* break_pc);
// Set or delete breakpoint (there can be only one).
bool SetBreakpoint(Instruction* breakpc);
void DeleteBreakpoint();
// Undo and redo all breakpoints. This is needed to bracket disassembly and
// execution to skip past breakpoints when run from the debugger.
void UndoBreakpoints();
void RedoBreakpoints();
// Undo and redo the breakpoint. This is needed to bracket disassembly and
// execution to skip past the breakpoint when run from the debugger.
void UndoBreakpoint();
void RedoBreakpoint();
};
void S390Debugger::Stop(Instruction* instr) {
// Get the stop code.
// use of kStopCodeMask not right on PowerPC
uint32_t code = instr->SvcValue() & kStopCodeMask;
// Retrieve the encoded address, which comes just after this stop.
char* msg = *reinterpret_cast<char**>(sim_->get_pc() + sizeof(FourByteInstr));
// Update this stop description.
if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
sim_->watched_stops_[code].desc = msg;
}
// Print the stop message and code if it is not the default code.
if (code != kMaxStopCode) {
PrintF("Simulator hit stop %u: %s\n", code, msg);
} else {
PrintF("Simulator hit %s\n", msg);
}
sim_->set_pc(sim_->get_pc() + sizeof(FourByteInstr) + kPointerSize);
Debug();
void Simulator::DebugAtNextPC() {
PrintF("Starting debugger on the next instruction:\n");
set_pc(get_pc() + sizeof(FourByteInstr));
S390Debugger(this).Debug();
}
intptr_t S390Debugger::GetRegisterValue(int regnum) {
......@@ -147,25 +132,33 @@ bool S390Debugger::SetBreakpoint(Instruction* break_pc) {
return true;
}
bool S390Debugger::DeleteBreakpoint(Instruction* break_pc) {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
}
namespace {
// This function is dangerous, but it's only available in non-production
// (simulator) builds.
void SetInstructionBitsInCodeSpace(Instruction* instr, Instr value,
Heap* heap) {
CodeSpaceMemoryModificationScope scope(heap);
instr->SetInstructionBits(value);
}
} // namespace
void S390Debugger::DeleteBreakpoint() {
UndoBreakpoint();
sim_->break_pc_ = nullptr;
sim_->break_instr_ = 0;
return true;
}
void S390Debugger::UndoBreakpoints() {
void S390Debugger::UndoBreakpoint() {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
SetInstructionBitsInCodeSpace(sim_->break_pc_, sim_->break_instr_,
sim_->isolate_->heap());
}
}
void S390Debugger::RedoBreakpoints() {
void S390Debugger::RedoBreakpoint() {
if (sim_->break_pc_ != nullptr) {
sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
SetInstructionBitsInCodeSpace(sim_->break_pc_, kBreakpointInstr,
sim_->isolate_->heap());
}
}
......@@ -189,9 +182,9 @@ void S390Debugger::Debug() {
arg1[ARG_SIZE] = 0;
arg2[ARG_SIZE] = 0;
// Undo all set breakpoints while running in the debugger shell. This will
// make them invisible to all commands.
UndoBreakpoints();
// Unset breakpoint while running in the debugger shell, making it invisible
// to all commands.
UndoBreakpoint();
// Disable tracing while simulating
bool trace = ::v8::internal::FLAG_trace_sim;
::v8::internal::FLAG_trace_sim = false;
......@@ -498,9 +491,7 @@ void S390Debugger::Debug() {
PrintF("break <address>\n");
}
} else if (strcmp(cmd, "del") == 0) {
if (!DeleteBreakpoint(nullptr)) {
PrintF("deleting breakpoint failed\n");
}
DeleteBreakpoint();
} else if (strcmp(cmd, "cr") == 0) {
PrintF("Condition reg: %08x\n", sim_->condition_reg_);
} else if (strcmp(cmd, "stop") == 0) {
......@@ -513,7 +504,8 @@ void S390Debugger::Debug() {
if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
// Remove the current stop.
if (sim_->isStopInstruction(stop_instr)) {
stop_instr->SetInstructionBits(kNopInstr);
SetInstructionBitsInCodeSpace(stop_instr, kNopInstr,
sim_->isolate_->heap());
msg_address->SetInstructionBits(kNopInstr);
} else {
PrintF("Not at debugger stop.\n");
......@@ -627,9 +619,9 @@ void S390Debugger::Debug() {
}
}
// Add all the breakpoints back to stop execution and enter the debugger
// shell when hit.
RedoBreakpoints();
// Reinstall breakpoint to stop execution and enter the debugger shell when
// hit.
RedoBreakpoint();
// Restore tracing
::v8::internal::FLAG_trace_sim = trace;
......@@ -2202,13 +2194,11 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
set_pc(saved_lr);
break;
}
case kBreakpoint: {
S390Debugger dbg(this);
dbg.Debug();
case kBreakpoint:
S390Debugger(this).Debug();
break;
}
// stop uses all codes greater than 1 << 23.
default: {
default:
if (svc >= (1 << 23)) {
uint32_t code = svc & kStopCodeMask;
if (isWatchedStop(code)) {
......@@ -2217,17 +2207,19 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
// Stop if it is enabled, otherwise go on jumping over the stop
// and the message address.
if (isEnabledStop(code)) {
S390Debugger dbg(this);
dbg.Stop(instr);
if (code != kMaxStopCode) {
PrintF("Simulator hit stop %u. ", code);
} else {
PrintF("Simulator hit stop. ");
}
DebugAtNextPC();
} else {
set_pc(get_pc() + sizeof(FourByteInstr) + kPointerSize);
}
} else {
// This is not a valid svc code.
UNREACHABLE();
break;
}
}
}
}
......
......@@ -230,6 +230,7 @@ class Simulator : public SimulatorBase {
void HandleRList(Instruction* instr, bool load);
void HandleVList(Instruction* inst);
void SoftwareInterrupt(Instruction* instr);
void DebugAtNextPC();
// Stop helper functions.
inline bool isStopInstruction(Instruction* instr);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment