[arm64/sim] Add a 'sim' gdb command

Extract out the command processing from Simulator::Debug(), and expose
it to gdb as a new 'sim' command. Example usage:

    (gdb) sim p x15
    (gdb) sim stack

The sim command will execute that one command, and will return to gdb.

For a list of all commands, you can call

    (gdb) sim help

Note that sim won't resume simulator execution until gdb continues
execution; for example, `sim next` will set a breakpoint on the next
instruction, and will return to gdb. The user then has to continue
execution in gdb, at which point the simulator will break. The user can
then re-enter gdb with the gdb command. This will look like this:

    (gdb) sim next
    (gdb) continue
    ...
    sim> gdb
    (gdb) ...

Change-Id: I678e71e2642d8427950b5f7ed65890ceae69e18d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2664448
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72479}
This commit is contained in:
Leszek Swirski 2021-02-02 12:01:05 +01:00 committed by Commit Bot
parent 1f85cb19df
commit 1f72df06b3
5 changed files with 347 additions and 290 deletions

View File

@ -2744,12 +2744,12 @@ V8_EXPORT_PRIVATE extern void _v8_internal_Print_Code(void* object) {
} }
if (!isolate->heap()->InSpaceSlow(address, i::CODE_SPACE) && if (!isolate->heap()->InSpaceSlow(address, i::CODE_SPACE) &&
!isolate->heap()->InSpaceSlow(address, i::LO_SPACE) && !isolate->heap()->InSpaceSlow(address, i::CODE_LO_SPACE) &&
!i::InstructionStream::PcIsOffHeap(isolate, address) && !i::InstructionStream::PcIsOffHeap(isolate, address) &&
!i::ReadOnlyHeap::Contains(address)) { !i::ReadOnlyHeap::Contains(address)) {
i::PrintF( i::PrintF(
"%p is not within the current isolate's large object, code, read_only " "%p is not within the current isolate's code, read_only or embedded "
"or embedded spaces\n", "spaces\n",
object); object);
return; return;
} }

View File

@ -4,6 +4,8 @@
#include "src/execution/arm64/simulator-arm64.h" #include "src/execution/arm64/simulator-arm64.h"
#include "src/execution/isolate.h"
#if defined(USE_SIMULATOR) #if defined(USE_SIMULATOR)
#include <stdlib.h> #include <stdlib.h>
@ -378,7 +380,6 @@ Simulator::~Simulator() {
delete[] reinterpret_cast<byte*>(stack_); delete[] reinterpret_cast<byte*>(stack_);
delete disassembler_decoder_; delete disassembler_decoder_;
delete print_disasm_; delete print_disasm_;
DeleteArray(last_debugger_input_);
delete decoder_; delete decoder_;
} }
@ -3291,6 +3292,17 @@ bool Simulator::PrintValue(const char* desc) {
} }
void Simulator::Debug() { void Simulator::Debug() {
bool done = false;
while (!done) {
// Disassemble the next instruction to execute before doing anything else.
PrintInstructionsAt(pc_, 1);
// Read the command line.
ArrayUniquePtr<char> line(ReadLine("sim> "));
done = ExecDebugCommand(std::move(line));
}
}
bool Simulator::ExecDebugCommand(ArrayUniquePtr<char> line_ptr) {
#define COMMAND_SIZE 63 #define COMMAND_SIZE 63
#define ARG_SIZE 255 #define ARG_SIZE 255
@ -3307,25 +3319,19 @@ void Simulator::Debug() {
arg1[ARG_SIZE] = 0; arg1[ARG_SIZE] = 0;
arg2[ARG_SIZE] = 0; arg2[ARG_SIZE] = 0;
bool done = false;
bool cleared_log_disasm_bit = false; bool cleared_log_disasm_bit = false;
while (!done) { if (line_ptr == nullptr) return false;
// Disassemble the next instruction to execute before doing anything else.
PrintInstructionsAt(pc_, 1);
// Read the command line.
char* line = ReadLine("sim> ");
if (line == nullptr) {
break;
} else {
// Repeat last command by default. // Repeat last command by default.
char* last_input = last_debugger_input(); const char* line = line_ptr.get();
const char* last_input = last_debugger_input();
if (strcmp(line, "\n") == 0 && (last_input != nullptr)) { if (strcmp(line, "\n") == 0 && (last_input != nullptr)) {
DeleteArray(line); line_ptr.reset();
line = last_input; line = last_input;
} else { } else {
// Update the latest command ran // Update the latest command ran
set_last_debugger_input(line); set_last_debugger_input(std::move(line_ptr));
} }
// Use sscanf to parse the individual parts of the command line. At the // Use sscanf to parse the individual parts of the command line. At the
@ -3369,19 +3375,19 @@ void Simulator::Debug() {
// Tell the simulator to break after the next executed BL. // Tell the simulator to break after the next executed BL.
break_on_next_ = true; break_on_next_ = true;
// Continue. // Continue.
done = true; return true;
// continue / cont / c // continue / cont / c
// --------------------------------------------------- // ---------------------------------------------------
} else if ((strcmp(cmd, "continue") == 0) || (strcmp(cmd, "cont") == 0) || } else if ((strcmp(cmd, "continue") == 0) || (strcmp(cmd, "cont") == 0) ||
(strcmp(cmd, "c") == 0)) { (strcmp(cmd, "c") == 0)) {
// Leave the debugger shell. // Leave the debugger shell.
done = true; return true;
// disassemble / disasm / di // disassemble / disasm / di
// --------------------------------------------- // ---------------------------------------------
} else if (strcmp(cmd, "disassemble") == 0 || } else if (strcmp(cmd, "disassemble") == 0 || strcmp(cmd, "disasm") == 0 ||
strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) { strcmp(cmd, "di") == 0) {
int64_t n_of_instrs_to_disasm = 10; // default value. int64_t n_of_instrs_to_disasm = 10; // default value.
int64_t address = reinterpret_cast<int64_t>(pc_); // default value. int64_t address = reinterpret_cast<int64_t>(pc_); // default value.
if (argc >= 2) { // disasm <n of instrs> if (argc >= 2) { // disasm <n of instrs>
@ -3418,8 +3424,7 @@ void Simulator::Debug() {
// printobject / po // printobject / po
// ------------------------------------------------------ // ------------------------------------------------------
} else if ((strcmp(cmd, "printobject") == 0) || } else if ((strcmp(cmd, "printobject") == 0) || (strcmp(cmd, "po") == 0)) {
(strcmp(cmd, "po") == 0)) {
if (argc == 2) { if (argc == 2) {
int64_t value; int64_t value;
StdoutStream os; StdoutStream os;
@ -3457,7 +3462,7 @@ void Simulator::Debug() {
int64_t value; int64_t value;
if (!GetValue(arg1, &value)) { if (!GetValue(arg1, &value)) {
PrintF("%s unrecognized\n", arg1); PrintF("%s unrecognized\n", arg1);
continue; return false;
} }
cur = reinterpret_cast<int64_t*>(value); cur = reinterpret_cast<int64_t*>(value);
next_arg++; next_arg++;
@ -3587,11 +3592,11 @@ void Simulator::Debug() {
PrintF("Unknown command: %s\n", cmd); PrintF("Unknown command: %s\n", cmd);
PrintF("Use 'help' for more information.\n"); PrintF("Use 'help' for more information.\n");
} }
}
if (cleared_log_disasm_bit == true) { if (cleared_log_disasm_bit == true) {
set_log_parameters(log_parameters_ | LOG_DISASM); set_log_parameters(log_parameters_ | LOG_DISASM);
} }
} return false;
} }
void Simulator::VisitException(Instruction* instr) { void Simulator::VisitException(Instruction* instr) {
@ -6137,4 +6142,26 @@ void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
//
// The following functions are used by our gdb macros.
//
V8_EXPORT_PRIVATE extern bool _v8_internal_Simulator_ExecDebugCommand(
const char* command) {
i::Isolate* isolate = i::Isolate::Current();
if (!isolate) {
fprintf(stderr, "No V8 Isolate found\n");
return false;
}
i::Simulator* simulator = i::Simulator::current(isolate);
if (!simulator) {
fprintf(stderr, "No Arm64 simulator found\n");
return false;
}
// Copy the command so that the simulator can take ownership of it.
size_t len = strlen(command);
i::ArrayUniquePtr<char> command_copy(i::NewArray<char>(len + 1));
i::MemCopy(command_copy.get(), command, len + 1);
return simulator->ExecDebugCommand(std::move(command_copy));
}
#endif // USE_SIMULATOR #endif // USE_SIMULATOR

View File

@ -731,6 +731,11 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
// Start the debugging command line. // Start the debugging command line.
void Debug(); void Debug();
// Executes a single debug command. Takes ownership of the command (so that it
// can store it for repeat executions), and returns true if the debugger
// should resume execution after this command completes.
bool ExecDebugCommand(ArrayUniquePtr<char> command);
bool GetValue(const char* desc, int64_t* value); bool GetValue(const char* desc, int64_t* value);
bool PrintValue(const char* desc); bool PrintValue(const char* desc);
@ -2327,12 +2332,11 @@ class Simulator : public DecoderVisitor, public SimulatorBase {
static const char* vreg_names[]; static const char* vreg_names[];
// Debugger input. // Debugger input.
void set_last_debugger_input(char* input) { void set_last_debugger_input(ArrayUniquePtr<char> input) {
DeleteArray(last_debugger_input_); last_debugger_input_ = std::move(input);
last_debugger_input_ = input;
} }
char* last_debugger_input() { return last_debugger_input_; } const char* last_debugger_input() { return last_debugger_input_.get(); }
char* last_debugger_input_; ArrayUniquePtr<char> last_debugger_input_;
// Synchronization primitives. See ARM DDI 0487A.a, B2.10. Pair types not // Synchronization primitives. See ARM DDI 0487A.a, B2.10. Pair types not
// implemented. // implemented.

View File

@ -57,6 +57,14 @@ void DeleteArray(T* array) {
delete[] array; delete[] array;
} }
template <typename T>
struct ArrayDeleter {
void operator()(T* array) { DeleteArray(array); }
};
template <typename T>
using ArrayUniquePtr = std::unique_ptr<T, ArrayDeleter<T>>;
// The normal strdup functions use malloc. These versions of StrDup // The normal strdup functions use malloc. These versions of StrDup
// and StrNDup uses new and calls the FatalProcessOutOfMemory handler // and StrNDup uses new and calls the FatalProcessOutOfMemory handler
// if allocation fails. // if allocation fails.

View File

@ -86,6 +86,24 @@ Skip the jitted stack on x64 to where we entered JS last.
Usage: jss Usage: jss
end end
# Execute a simulator command.
python
import gdb
class SimCommand(gdb.Command):
"""Sim the current program."""
def __init__ (self):
super (SimCommand, self).__init__ ("sim", gdb.COMMAND_SUPPORT)
def invoke (self, arg, from_tty):
arg_c_string = gdb.Value(arg)
cmd_func = gdb.selected_frame().read_var("_v8_internal_Simulator_ExecDebugCommand")
cmd_func(arg_c_string)
SimCommand()
end
# Print stack trace with assertion scopes. # Print stack trace with assertion scopes.
define bta define bta
python python