Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Checks: '-modernize-use-nullptr'
57 changes: 42 additions & 15 deletions doc/reference/dap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ DAP support
DAP (debugger adapter protocol) is a protocol that enables standardized communication
between development tools (IDEs) and debuggers.

An experimental DAP support now arrived to MSIM, allowing DAP-enabled IDEs to connect to
the running MSIM for interactive debugging.
DAP support is integrated to MSIM, allowing DAP-enabled IDEs to connect to
the running MSIM for interactive debugging via a debugging adapter.

Currently the only supported and tested IDE is Visual Studio Code with the provided
`msim-debugger extension <https://github.com/0xVector/msim-debugger>`_.
Expand All @@ -31,9 +31,9 @@ in future releases.
Breakpoints
~~~~~~~~~~~

The first supported debugging feature are simple breakpoints.
Code breakpoints are fully supported.
You can set breakpoints in your IDE, and when MSIM hits them during execution,
it will enter interactive mode to allow you to e.g. inspect CPU registers.extension
it will pause and wait for further commands from the IDE.

This can be useful to pause execution at specific points in your program and
examine the state of your kernel.
Expand All @@ -46,25 +46,52 @@ It is conceptually similar to adding a breakpoint via the special `ebreak` instr
as described in :ref:`entering-the-debugger`.

When stopped at a breakpoint, you can resume the execution just as you would normally,
using the ``continue`` command.
using the resume command in your IDE.

Limitations
^^^^^^^^^^^
Execution control
~~~~~~~~~~~~~~~~~

MSIM can be paused and resumed from the IDE, allowing you to control the execution of your kernel.

Register Inspection
~~~~~~~~~~~~~~~~~~~

When MSIM is paused, you can inspect the values of the registers in your kernel from the IDE.
Both general-purpose and control/status registers are supported. The registers are displayed
in the IDE's variables view, and their values can be modified.

Memory Inspection
~~~~~~~~~~~~~~~~~

When MSIM is paused, you can inspect the memory of your kernel from the IDE.
The memory view in the IDE allows you to view and modify the contents of the memory at specific addresses.
This is done by clicking the memory view next to a register with pointer-like semantics.

You can't remove the breakpoints when MSIM is running yet.
You need to restart MSIM and the debugging session after removing them in your IDE.
CPU View
~~~~~~~~

The IDE is currently not aware when and where MSIM stops,
this is a planned feature in next releases.
The CPUs in MSIM are displayed in the IDE, presented as threads. You can see the highlighted CPU when MSIM
is paused, denoting the CPU causing the stopping.

Stepping
~~~~~~~~

Stepping is supported, allowing you to step through your kernel's execution one instruction at a time.
The step-in command steps by one instruction, while the step-over command attempts to step to the next statement.
The step-out command is not supported yet, defaulting to step-in behavior.

Limitations
^^^^^^^^^^^

Some sources files might not be correctly mapped to the memory addresses, and
will not have the breakpoints hit.
will not have the breakpoints hit. This happens especially when entering a userspace application,
as that is usually built as a separate ELF file, which the extension has no access to.

The step-out command is not supported yet.

Bug reports and feedback
------------------------

This extension is *very* experimental and a work in progress.

Please, report any bugs or feedback you have to the `issues in the MSIM repository <https://github.com/d-iii-s/msim/issues>`_.
Please, report any bugs or feedback you have to the `issues in the MSIM repository <https://github.com/0xVector/msim/issues>`_.

Your bug reports and feedback are very much appreciated! :)
2 changes: 2 additions & 0 deletions src/assert.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#ifndef ASSERT_H_
#define ASSERT_H_

#include <assert.h>

#ifndef NDEBUG

#include "fault.h"
Expand Down
59 changes: 24 additions & 35 deletions src/debug/breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@

#include "../assert.h"
#include "../device/cpu/general_cpu.h"
#include "../device/cpu/mips_r4000/cpu.h"
#include "../device/cpu/riscv_rv32ima/cpu.h"
#include "../device/device.h"
#include "../device/dr4kcpu.h"
#include "../device/drvcpu.h"
#include "../fault.h"
#include "../main.h"
#include "../utils.h"
Expand Down Expand Up @@ -190,7 +185,11 @@ void physmem_breakpoint_hit(physmem_breakpoint_t *breakpoint,
machine_interactive = true;
break;
case BREAKPOINT_KIND_DEBUGGER:
gdb_handle_event(GDB_EVENT_BREAKPOINT);
if (dap_enabled) {
dap_event_hit_data_breakpoint(breakpoint->addr);
} else if (remote_gdb) {
gdb_handle_event(GDB_EVENT_BREAKPOINT);
}
break;
default:
die(ERR_INTERN, "Unexpected physical memory breakpoint kind");
Expand Down Expand Up @@ -224,19 +223,24 @@ breakpoint_t *breakpoint_init(ptr64_t address, breakpoint_kind_t kind)
/** Fires given breakpoint
*
* @param breakpoint Breakpoint structure to be fired
* @param cpu_no Number of CPU which hit the breakpoint.
*
*/
static void breakpoint_hit(breakpoint_t *breakpoint)
static void breakpoint_hit(breakpoint_t *breakpoint, unsigned long cpu_no)
{
breakpoint->hits++;

switch (breakpoint->kind) {
case BREAKPOINT_KIND_SIMULATOR:
alert("Debug: Hit breakpoint at %#0" PRIx64, breakpoint->pc.ptr);
alert("Debug: Hit simulator breakpoint at %#0" PRIx64, breakpoint->pc.ptr);
machine_interactive = true;
break;
case BREAKPOINT_KIND_DEBUGGER:
gdb_handle_event(GDB_EVENT_BREAKPOINT);
if (dap_enabled) {
dap_event_hit_code_breakpoint(cpu_no);
} else if (remote_gdb) {
gdb_handle_event(GDB_EVENT_BREAKPOINT);
}
break;
default:
die(ERR_INTERN, "Unexpected breakpoint kind");
Expand All @@ -246,23 +250,24 @@ static void breakpoint_hit(breakpoint_t *breakpoint)
/** Search for a breakpoint
*
* Search for a breakpoint in given list which should be
* fired on given address and fire it.
* fired based on address of given CPU's PC.
*
* @param breakpoints List of code breakpoints of some processor.
* @param address Address of executed instruction.
* @param cpu CPU which can hit the breakpoint.
*
* @return True, if at least one breakpoint has been hit.
*
*/
static bool breakpoint_hit_by_address(list_t breakpoints, ptr64_t address)
static bool breakpoint_hit_by_cpu(list_t breakpoints, general_cpu_t *cpu)
{
ptr64_t address = cpu_get_pc(cpu);
bool hit = false;

breakpoint_t *breakpoint = NULL;
for_each(breakpoints, breakpoint, breakpoint_t)
{
if (breakpoint->pc.ptr == address.ptr) {
breakpoint_hit(breakpoint);
breakpoint_hit(breakpoint, cpu->cpuno);
hit = true;
}
}
Expand Down Expand Up @@ -298,38 +303,22 @@ breakpoint_t *breakpoint_find_by_address(list_t breakpoints,
return NULL;
}

/** Search all of the processors
/** Search all the processors
*
* Search all of the processors whether any of them is going to
* Search all the processors whether any of them is going to
* execute instruction where a code breakpoint is located. All such
* breakpoints are fired.
*
* @return True, if at least one breakpoint has been fired.
*
*/
bool breakpoint_check_for_code_breakpoints(void)
{
bool hit = false;
device_t *dev = NULL;

while (dev_next(&dev, DEVICE_FILTER_R4K_PROCESSOR)) {
r4k_cpu_t *cpu = get_r4k(dev);

if (breakpoint_hit_by_address(cpu->bps, cpu->pc)) {
hit = true;
}
}

if (hit) {
return hit;
}

while (dev_next(&dev, DEVICE_FILTER_RV_PROCESSOR)) {
const rv_cpu_t *cpu = get_rv(dev);

ptr64_t addr = { 0 };
addr.lo = cpu->pc;
if (breakpoint_hit_by_address(cpu->bps, addr)) {
general_cpu_t *cpu = NULL;
for_each(cpu_list, cpu, general_cpu_t)
{
if (breakpoint_hit_by_cpu(cpu->bps, cpu)) {
hit = true;
}
}
Expand Down
Loading