blob: 4fb5df021a465ff0f29ada31cdbf75fe78ba049c [file] [log] [blame]
// Copyright 2023, VIXL authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of ARM Limited nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "test-debugger-aarch64.h"
namespace vixl {
namespace aarch64 {
#ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
// The debugger is only available to be tested in simulator builds.
TEST(breakpoints_invalid) {
SETUP();
// Test invalid strings instead of numbers.
SETUP_CMD("break a", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break abcdef", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break A", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break ABCDEF", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break 0x", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break 0xg", "Error: Use `break <address>` to set a breakpoint");
// Test different amounts of parameters.
SETUP_CMD("break", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break 42 52", "Error: Use `break <address>` to set a breakpoint");
// Test out of range addresses.
SETUP_CMD("break 0xFFFFFFFFFFFFFFFF1",
"Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("break 18446744073709551616",
"Error: Use `break <address>` to set a breakpoint");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(breakpoints_valid) {
SETUP();
// Test bottom boundary of addresses.
SETUP_CMD("break 0x0", "Breakpoint successfully added at: 0x0");
SETUP_CMD("break 0", "Breakpoint successfully removed at: 0x0");
SETUP_CMD("break 0x1", "Breakpoint successfully added at: 0x1");
SETUP_CMD("break 1", "Breakpoint successfully removed at: 0x1");
// Test top boundary of addresses.
SETUP_CMD("break 0xFFFFFFFFFFFFFFFF",
"Breakpoint successfully added at: 0xffffffffffffffff");
SETUP_CMD("break 18446744073709551615",
"Breakpoint successfully removed at: 0xffffffffffffffff");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(breakpoints_hit) {
SETUP();
// Test hitting a breakpoint.
std::string mov_addr = GET_INSTRUCTION_ADDRESS("mov x2, #0x2");
std::string break_cmd = "break ";
break_cmd += mov_addr;
std::string expected_trace = "Breakpoint successfully added at: ";
expected_trace += mov_addr;
SETUP_CMD(break_cmd, expected_trace);
SETUP_CMD("continue",
"Continuing...\n"
"Debugger hit breakpoint, breaking...");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(cmd_aliases) {
SETUP();
// Test all short form commands, to ensure they correctly run their long form
// counterparts.
SETUP_CMD("b", "Error: Use `break <address>` to set a breakpoint");
SETUP_CMD("s x",
"Error: use `step \\[number\\]` to step an optional number of"
" instructions");
SETUP_CMD("p",
"Error: use `print <register|all>` to print the contents of a"
" specific register or all registers.");
SETUP_CMD("t 1", "Error: use `trace` to toggle tracing of registers.");
SETUP_CMD("g 1",
"Error: use `gdb` to enter GDB from the simulator debugger.");
// Continue to exit the debugger.
SETUP_CMD("c", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_single) {
SETUP();
// Test single stepping through the whole program.
SETUP_CMD("step", ".*mov x2, #0x2");
SETUP_CMD("step", ".*sub x3, x1, x2");
SETUP_CMD("step", ".*ret");
SETUP_CMD("step",
".*Debugger at the end of simulation, leaving simulator...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_single_and_continue) {
SETUP();
// Test single stepping and then continuing.
SETUP_CMD("step", ".*mov x2, #0x2");
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_multi_1) {
SETUP();
// Test multi stepping a single instruction.
SETUP_CMD("step 1", ".*mov x2, #0x2");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_multi_2) {
SETUP();
// Test multi stepping two instructions.
SETUP_CMD("step 2",
".*mov x2, #0x2\n"
".*sub x3, x1, x2");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_multi_3) {
SETUP();
// Test multi stepping three instructions.
SETUP_CMD("step 3",
".*mov x2, #0x2\n"
".*sub x3, x1, x2\n"
".*ret");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_multi_4) {
SETUP();
// Test stepping through the whole program in one go.
SETUP_CMD("step 4",
".*mov x2, #0x2\n"
".*sub x3, x1, x2\n"
".*ret\n"
"Debugger at the end of simulation, leaving simulator...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_multi_5) {
SETUP();
// Test multi stepping past the end of the program.
SETUP_CMD("step 5",
".*mov x2, #0x2\n"
".*sub x3, x1, x2\n"
".*ret\n"
"Debugger at the end of simulation, leaving simulator...");
RUN();
CHECK_OUTPUT();
}
TEST(stepping_invalid) {
SETUP();
// Test invalid arguments to step command.
SETUP_CMD("step 1 2",
"Error: use `step \\[number\\]` to step an optional number of"
" instructions");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(print_invalid) {
SETUP();
// Test invalid amounts of arguments to the print command.
SETUP_CMD("print",
"Error: use `print <register|all>` to print the contents of a"
" specific register or all registers.");
SETUP_CMD("print all all",
"Error: use `print <register|all>` to print the contents of a"
" specific register or all registers.");
// Test invalid types of registers.
SETUP_CMD("print alls",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print a",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print x",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print 0",
"Error: incorrect register format, use e.g: X0, x0, etc...");
// Test registers that don't exist on AARCH64.
SETUP_CMD("print w32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print W32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print x32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print X32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print v32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
SETUP_CMD("print V32",
"Error: incorrect register format, use e.g: X0, x0, etc...");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(trace_invalid) {
SETUP();
// Test invalid arguments to trace command.
SETUP_CMD("trace 1 2", "Error: use `trace` to toggle tracing of registers.");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(trace_toggling) {
SETUP();
// Test toggling tracing.
SETUP_CMD("trace",
"Enabling disassembly, registers and memory write tracing");
SETUP_CMD("trace",
"Disabling disassembly, registers and memory write tracing");
SETUP_CMD("trace",
"Enabling disassembly, registers and memory write tracing");
SETUP_CMD("trace",
"Disabling disassembly, registers and memory write tracing");
// Continue to exit the debugger.
SETUP_CMD("continue", "Continuing...");
RUN();
CHECK_OUTPUT();
}
TEST(trace_full) {
SETUP();
// Test tracing the whole program.
SETUP_CMD("trace",
"Enabling disassembly, registers and memory write tracing");
std::string expected_trace = "Continuing...\n";
expected_trace += ".*add x1, x0, #0x5 \\(5\\)\n";
expected_trace += "(" + x_register_trace + "\\n){32}";
expected_trace += "(" + v_register_trace + "\\n){32}";
expected_trace += ".*mov x2, #0x2\n";
expected_trace += x_register_trace + "\n";
expected_trace += ".*sub x3, x1, x2\n";
expected_trace += x_register_trace + "\n";
expected_trace += ".*ret\n";
expected_trace += "# Branch to 0x0000000000000000.";
SETUP_CMD("continue", expected_trace);
RUN();
CHECK_OUTPUT();
}
TEST(trace_partial) {
SETUP();
// Test tracing a single line.
SETUP_CMD("trace",
"Enabling disassembly, registers and memory write tracing");
std::string expected_trace = ".*add x1, x0, #0x5 \\(5\\)\n";
expected_trace += "(" + x_register_trace + "\\n){32}";
expected_trace += "(" + v_register_trace + "\\n){32}";
expected_trace += ".*mov x2, #0x2\n";
SETUP_CMD("step", expected_trace);
SETUP_CMD("trace",
"Disabling disassembly, registers and memory write tracing");
SETUP_CMD("continue", "Continuing...\n");
RUN();
CHECK_OUTPUT();
}
#endif // VIXL_INCLUDE_SIMULATOR_AARCH64
} // namespace aarch64
} // namespace vixl