Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9e9ed12
vm,types: introduce dict type with value-key support
jow- Jun 27, 2026
e2e5bfa
vm: reliably stop execution on nested exit; add SIGWINCH signal
jow- May 31, 2024
a51cc30
chunk,compiler: optimize offset info, encode statement boundaries
jow- May 22, 2024
1bc8f23
vm: add breakpoint primitives
jow- Jun 20, 2024
ea89ab8
vm: export insn format table and argtype helper
jow- Jun 20, 2024
5c36064
lib: fix potential invalid memory access in uc_require_ucode()
jow- Jun 20, 2024
6013590
debug: add interactive command line debugger
jow- Jun 20, 2024
640073c
main: add command line switch to start debug mode
jow- Jun 20, 2024
ab27cad
debug: add non-interactive mode, SIGUSR1 break, -X flag
jow- Apr 8, 2026
fba7526
debug: add remote debug protocol with push notifications
jow- Jul 23, 2026
da60381
debug: give the remote protocol full parity with the local CLI
jow- Jul 23, 2026
d804569
debug: add debug.listen() for embedding hosts, fix signal-handler crash
jow- Jul 23, 2026
0bedc82
debug: fix remote session reconnect, stepping, add exit/exception events
jow- Jul 24, 2026
f6364dc
debug: move debugger onto a line-based protocol, split server/client
jow- Jul 26, 2026
aab35bc
debug: fix prompt races, port header bar/underline, style event lines
jow- Jul 26, 2026
2a058e8
debug: udbg loads source locally first, server SOURCE is a fallback
jow- Jul 26, 2026
c4dbf33
debug: fix column off-by-one, pad backtrace snippets, restore ellipsi…
jow- Jul 26, 2026
98a55e4
debug: fix infinite recursion arming BK_CATCH from an active pause
jow- Jul 26, 2026
f503f96
debug: port rich disassembly/variables rendering, fix help and backtr…
jow- Jul 26, 2026
1264cf1
debug: add line editing/history/completion, a SET command, sandbox eval
jow- Jul 26, 2026
73c3e00
debug: replace SET with EVAL, fix real mutation, mark shadowed variables
jow- Jul 26, 2026
204c7f8
debug: Ctrl-C in udbg interrupts a freely-running debuggee
jow- Jul 26, 2026
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
9 changes: 6 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,14 @@ set(LIBRARIES "")

if(DEBUG_SUPPORT)
set(LIBRARIES ${LIBRARIES} debug_lib)
add_library(debug_lib MODULE lib/debug.c)
add_library(debug_lib MODULE lib/debug.c lib/debug_remote.c lib/debug_proto.c)
set_target_properties(debug_lib PROPERTIES OUTPUT_NAME debug PREFIX "")
target_link_options(debug_lib PRIVATE ${UCODE_MODULE_LINK_OPTIONS})
target_link_libraries(debug_lib PRIVATE libucode)
if(libubox)
find_path(uloop_include_dir NAMES libubox/uloop.h)
include_directories(${uloop_include_dir})
target_link_libraries(debug_lib ${libubox} ${libucode})
target_link_libraries(debug_lib PRIVATE ${libubox} ${libucode})
target_compile_definitions(debug_lib PRIVATE HAVE_ULOOP)
endif()
endif()
Expand Down Expand Up @@ -451,7 +452,9 @@ if(UNIT_TESTING)
endif()
endif()

install(TARGETS ucode RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(udbg udbg.c debug_highlight.c debug_lineedit.c)
target_link_libraries(udbg PRIVATE libucode ${JSONC_LINK_LIBRARIES})
install(TARGETS ucode udbg RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS libucode LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(TARGETS ${LIBRARIES} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/ucode)

Expand Down
108 changes: 69 additions & 39 deletions chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@
#include "ucode/types.h"
#include "ucode/util.h"

#define OFFSETINFO_BITS (sizeof(((uc_offsetinfo_t *)NULL)->entries[0]) * 8)
#define OFFSETINFO_BYTE_BITS 3
#define OFFSETINFO_INSN_BITS (OFFSETINFO_BITS - OFFSETINFO_BYTE_BITS)
#define OFFSETINFO_MAX_BYTES ((1 << OFFSETINFO_BYTE_BITS) - 1)
#define OFFSETINFO_MAX_INSNS ((1 << OFFSETINFO_INSN_BITS) - 1)
#define OFFSETINFO_NUM_BYTES(n) ((n) & OFFSETINFO_MAX_BYTES)
#define OFFSETINFO_NUM_INSNS(n) ((n) >> OFFSETINFO_BYTE_BITS)
#define OFFSETINFO_ENCODE(line, insns) ((line & OFFSETINFO_MAX_BYTES) | (((insns) << OFFSETINFO_BYTE_BITS) & ~OFFSETINFO_MAX_BYTES))
#define OFFSETINFO_MAX_BYTES 127
#define OFFSETINFO_MAX_INSNS 127
#define OFFSETINFO_NUM_BYTES(o) ((o)->bytes & OFFSETINFO_MAX_BYTES)
#define OFFSETINFO_NUM_INSNS(o) ((o)->insns & OFFSETINFO_MAX_INSNS)
#define OFFSETINFO_IS_END(o) ((o)->insns & 0x80)


void
Expand Down Expand Up @@ -69,81 +66,114 @@ uc_chunk_add(uc_chunk_t *chunk, uint8_t byte, size_t offset)

uc_vector_push(chunk, byte);

/* offset info is encoded in bytes, for each byte, the first three bits
* specify the number of source text bytes to advance since the last entry
* and the remaining five bits specify the amount of instructions belonging
* to any given source text offset */
/* Offset info is encoded in byte pairs, the first byte specifies the number
* of source text bytes to advance since the last entry and the second byte
* specifies the amount of instructions belonging to the source text offset.
* Byte and instruction count values are limited to 7 bits (0x00..0x7f),
* the most significant bit in each byte is reserved as flag value; if the
* bit is set in the first byte, it signals the begin of a logical statement
* while a set bit in the second byte denotes the end of the statement. */
if (offset > 0 || offsets->count == 0) {
/* if this offset is farther than seven (2 ** 3 - 1) bytes apart from
/* If this offset is farther than 127 (2 ** 7 - 1) bytes apart from
* the last one, we need to emit intermediate "jump" bytes with zero
* instructions each */
for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) {
/* advance by 7 bytes */
uc_vector_push(offsets, OFFSETINFO_ENCODE(OFFSETINFO_MAX_BYTES, 0));
/* advance by 127 bytes */
uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 });
}

/* advance by `i` bytes, count one instruction */
uc_vector_push(offsets, OFFSETINFO_ENCODE(i, 1));
uc_vector_push(offsets, { i, 1 });
}

/* update instruction count at current offset entry */
else {
/* since we encode the per-offset instruction count in five bits, we
* can only count up to 31 instructions. If we exceed that limit,
* emit another offset entry with the initial three bits set to zero */
if (OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]) >= OFFSETINFO_MAX_INSNS) {
uc_offset_t *o = uc_vector_last(offsets);

/* since we encode the per-offset instruction count in seven bits, we
* can only count up to 127 instructions. If we exceed that limit,
* emit another offset entry with the byte offset set to zero */
if (OFFSETINFO_NUM_INSNS(o) >= OFFSETINFO_MAX_INSNS) {
/* advance by 0 bytes, count one instruction */
uc_vector_push(offsets, OFFSETINFO_ENCODE(0, 1));
uc_vector_push(offsets, { 0, 1 });
}
else {
uint8_t *prev = uc_vector_last(offsets);

*prev = OFFSETINFO_ENCODE(
OFFSETINFO_NUM_BYTES(*prev),
OFFSETINFO_NUM_INSNS(*prev) + 1);
o->insns++;
}
}

return chunk->count - 1;
}

void
uc_chunk_pop(uc_chunk_t *chunk)
uc_chunk_stmt_start(uc_chunk_t *chunk, size_t offset)
{
uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets;
int n_insns;
size_t i;

assert(chunk->count > 0);
for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) {
/* advance by 127 bytes */
uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 });
}

chunk->count--;
/* advance by `i` bytes, set start of statement flag */
uc_vector_push(offsets, { i | 0x80, 0 });
}

n_insns = OFFSETINFO_NUM_INSNS(offsets->entries[offsets->count - 1]);
void
uc_chunk_stmt_end(uc_chunk_t *chunk, size_t offset)
{
uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets;
uc_offset_t *o = offsets->count ? uc_vector_last(offsets) : NULL;
size_t i;

if (n_insns > 0) {
uint8_t *prev = uc_vector_last(offsets);
for (i = offset; i > OFFSETINFO_MAX_BYTES; i -= OFFSETINFO_MAX_BYTES) {
/* advance by 127 bytes */
uc_vector_push(offsets, { OFFSETINFO_MAX_BYTES, 0 });
}

*prev = OFFSETINFO_ENCODE(OFFSETINFO_NUM_BYTES(*prev), n_insns - 1);
if (i > 0 || o == NULL || OFFSETINFO_IS_END(o)) {
/* advance by `i` bytes, set start of statement flag */
uc_vector_push(offsets, { i, 0x80 });
}
else {
offsets->count--;
/* set end flag on last offset entry */
o->insns |= 0x80;
}
}

void
uc_chunk_pop(uc_chunk_t *chunk)
{
assert(chunk->count > 0);

chunk->count--;

for (size_t i = chunk->debuginfo.offsets.count; i > 0; i--) {
uc_offset_t *o = &chunk->debuginfo.offsets.entries[i - 1];

if (o->insns & 127) {
o->insns = ((o->insns & 127) - 1) | (o->insns & 128);
break;
}
}
}

size_t
uc_chunk_debug_get_srcpos(uc_chunk_t *chunk, size_t off)
{
uc_offsetinfo_t *offsets = &chunk->debuginfo.offsets;
size_t i, inum = 0, lnum = 0;
size_t i, inum = 0, bnum = 0;

if (!offsets->count)
return 0;

for (i = 0; i < offsets->count && inum < off; i++) {
lnum += OFFSETINFO_NUM_BYTES(offsets->entries[i]);
inum += OFFSETINFO_NUM_INSNS(offsets->entries[i]);
bnum += OFFSETINFO_NUM_BYTES(&offsets->entries[i]);
inum += OFFSETINFO_NUM_INSNS(&offsets->entries[i]);
}

return lnum;
return bnum;
}

void
Expand Down
Loading
Loading