Skip to content

Commit

Permalink
fixup! Teach the BEAM loader to load debug information
Browse files Browse the repository at this point in the history
  • Loading branch information
bjorng committed Sep 4, 2024
1 parent d5fb64e commit 4561f98
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 63 deletions.
179 changes: 118 additions & 61 deletions erts/emulator/beam/beam_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,16 +656,17 @@ static int parse_type_chunk(BeamFile *beam, IFF_Chunk *chunk) {

static int parse_debug_chunk_data(BeamFile *beam, BeamReader *p_reader) {
Sint32 count;
Sint32 num_vars;
Sint32 total_num_vars;
int i;
BeamOpAllocator op_allocator;
BeamCodeReader *op_reader;
BeamOp* op = NULL;
BeamFile_DebugTable *debug = &beam->debug;
Eterm *tp;
byte *lp;

LoadAssert(beamreader_read_i32(p_reader, &count));
LoadAssert(beamreader_read_i32(p_reader, &num_vars));
LoadAssert(beamreader_read_i32(p_reader, &total_num_vars));

beamopallocator_init(&op_allocator);

Expand All @@ -677,15 +678,23 @@ static int parse_debug_chunk_data(BeamFile *beam, BeamReader *p_reader) {
op_reader->first = 1;
op_reader->reader = *p_reader;

debug->count = count;
if (count < 0 || total_num_vars < 0) {
goto error;
}

debug->item_count = count;
debug->total_var_count = total_num_vars;
debug->items = erts_alloc(ERTS_ALC_T_PREPARED_CODE, count * sizeof(BeamFile_DebugItem));
debug->terms = erts_alloc(ERTS_ALC_T_PREPARED_CODE, 2 * num_vars * sizeof(Eterm));
debug->terms = erts_alloc(ERTS_ALC_T_PREPARED_CODE, 2 * total_num_vars * sizeof(Eterm));
debug->is_literal = erts_alloc(ERTS_ALC_T_PREPARED_CODE, 2 * total_num_vars * sizeof(Eterm));

tp = debug->terms;
lp = debug->is_literal;

for (i = 0; i < count; i++) {
BeamOpArg *arg;
int extra_args;
Sint32 num_vars;

if (!beamcodereader_next(op_reader, &op)) {
goto error;
Expand Down Expand Up @@ -716,109 +725,87 @@ static int parse_debug_chunk_data(BeamFile *beam, BeamReader *p_reader) {

arg++;

debug->items[i].num_vars = extra_args / 2;
num_vars = extra_args / 2;
if (2 * num_vars != extra_args || num_vars > total_num_vars) {
goto error;
}
total_num_vars -= num_vars;

debug->items[i].num_vars = num_vars;
debug->items[i].first = tp;

while (extra_args > 0) {
Eterm var_name;
byte *base;
Uint offset;
Uint size;

if (arg[0].type != TAG_q) {
goto error;
}

var_name = beamfile_get_literal(beam, arg[0].val);
if (!is_bitstring(var_name)) {
goto error;
}
*tp++ = var_name;

ERTS_GET_BITSTRING(var_name, base, offset, size);
if (offset != 0 || size % 8 != 0) {
if (!is_bitstring(var_name) || TAIL_BITS(bitstring_size(var_name))) {
goto error;
}
*tp++ = arg[0].val;
*lp++ = 1;

*lp = 0;
switch (arg[1].type) {
case TAG_i:
*tp++ = make_small(arg[1].val);
*tp = make_small(arg[1].val);
break;
case TAG_a:
*tp++ = arg[1].val;
*tp = arg[1].val;
break;
case TAG_x:
*tp++ = make_loader_x_reg(arg[1].val);
*tp = make_loader_x_reg(arg[1].val);
break;
case TAG_y:
*tp++ = make_loader_y_reg(arg[1].val);
*tp = make_loader_y_reg(arg[1].val);
break;
case TAG_q:
*tp++ = beamfile_get_literal(beam, arg[1].val);
*tp = arg[1].val;
*lp = 1;
break;
default:
goto error;
}

tp++, lp++;
arg += 2;
extra_args -= 2;
}

if (extra_args < 0) {
goto error;
}

beamopallocator_free_op(&op_allocator, op);
op = NULL;
}

if (total_num_vars != 0) {
goto error;
}

beamcodereader_close(op_reader);
beamopallocator_dtor(&op_allocator);

erts_printf("DbgB: %T: %d %d\n", beam->module, count, num_vars);

for (i = 0; i < debug->count; i++) {
Sint32 frame_size = debug->items[i].frame_size;
Sint32 num_vars = debug->items[i].num_vars;
Eterm *tp = debug->items[i].first;

if (frame_size < 0) {
erts_printf("%d: no stack frame\n", i + 1);
} else {
erts_printf("%d: %d\n", i + 1, frame_size);
}

while (num_vars-- > 0) {
byte *base;
ERTS_DECLARE_DUMMY(Uint offset);
Uint size;

ERTS_GET_BITSTRING(*tp, base, offset, size);
erts_printf(" %.*s ", size / 8, base);
tp++;

if (_is_loader_x_reg(*tp)) {
erts_printf("{x,%ld}", loader_x_reg_index(*tp));
} else if (_is_loader_y_reg(*tp)) {
erts_printf("{y,%ld}", loader_y_reg_index(*tp));
} else {
erts_printf("%T", *tp);
}
tp++;

erts_printf("\n");
}

erts_printf("\n");
}

return 1;

error:
if (op != NULL) {
beamopallocator_free_op(&op_allocator, op);
}

beamcodereader_close(op_reader);
beamopallocator_dtor(&op_allocator);

if (debug->items) {
erts_free(ERTS_ALC_T_PREPARED_CODE, debug->items);
debug->items = NULL;
}

if (debug->terms) {
erts_free(ERTS_ALC_T_PREPARED_CODE, debug->terms);
debug->terms = NULL;
}

return 0;
}

Expand Down Expand Up @@ -1349,9 +1336,11 @@ void beamfile_free(BeamFile *beam) {
if (beam->debug.items) {
erts_free(ERTS_ALC_T_PREPARED_CODE, beam->debug.items);
erts_free(ERTS_ALC_T_PREPARED_CODE, beam->debug.terms);
erts_free(ERTS_ALC_T_PREPARED_CODE, beam->debug.is_literal);

beam->debug.items = NULL;
beam->debug.terms = NULL;
beam->debug.is_literal = NULL;
}

if (beam->static_literals.entries) {
Expand Down Expand Up @@ -1475,6 +1464,72 @@ static void move_literal_entries(BeamFile_LiteralEntry *entries, int count,
}
}

static void adjust_debug_info(BeamFile *beam) {
int i;
Sint32 count;
BeamFile_DebugTable *debug = &beam->debug;

if (debug->item_count == 0) {
return;
}

count = 2 * debug->total_var_count;
for (i = 0; i < count; i++) {
Eterm val = debug->terms[i];

ASSERT(debug->is_literal[i] == 0 || debug->is_literal[i] == 1);
if (debug->is_literal[i]) {
debug->terms[i] = beamfile_get_literal(beam, val);
}

#ifdef DEBUG
/* This trick will only work once. */
debug->is_literal[i] = 2;
#endif
}

if (debug->item_count != 0) {
erts_printf("DbgB: %T\n", beam->module);
}

for (i = 0; i < debug->item_count; i++) {
Sint32 frame_size = debug->items[i].frame_size;
Sint32 num_vars = debug->items[i].num_vars;
Eterm *tp = debug->items[i].first;

if (frame_size < 0) {
erts_printf("%d: no stack frame\n", i + 1);
} else {
erts_printf("%d: %d\n", i + 1, frame_size);
}

while (num_vars-- > 0) {
const byte *temp_alloc = NULL;
const byte *str;
Uint size;

ASSERT(is_bitstring(*tp));
str = erts_get_aligned_binary_bytes(*tp, &size, &temp_alloc);
erts_printf(" %.*s ", size, str);
erts_free_aligned_binary_bytes(temp_alloc);
tp++;

if (_is_loader_x_reg(*tp)) {
erts_printf("{x,%ld}", loader_x_reg_index(*tp));
} else if (_is_loader_y_reg(*tp)) {
erts_printf("{y,%ld}", loader_y_reg_index(*tp));
} else {
erts_printf("%T", *tp);
}
tp++;

erts_printf("\n");
}

erts_printf("\n");
}
}

void beamfile_move_literals(BeamFile *beam, Eterm **hpp, ErlOffHeap *oh) {
BeamFile_LiteralTable *literals;

Expand All @@ -1483,6 +1538,8 @@ void beamfile_move_literals(BeamFile *beam, Eterm **hpp, ErlOffHeap *oh) {

literals = &beam->dynamic_literals;
move_literal_entries(literals->entries, literals->count, hpp, oh);

adjust_debug_info(beam);
}

int iff_init(const byte *data, size_t size, IFF_File *iff) {
Expand Down
4 changes: 3 additions & 1 deletion erts/emulator/beam/beam_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,11 @@ typedef struct {
} BeamFile_DebugItem;

typedef struct {
Sint32 count;
Sint32 item_count;
Sint32 total_var_count;
BeamFile_DebugItem *items;
Eterm *terms;
byte *is_literal;
} BeamFile_DebugTable;

typedef struct {
Expand Down
3 changes: 2 additions & 1 deletion lib/compiler/src/beam_asm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,8 @@ build_beam_debug_info_1(ExtraChunks0, Dict0) ->
NumItems = length(Contents0),
Contents1 = iolist_to_binary(Contents0),

0 = NumVars bsr 31, %Assertion.
0 = NumItems bsr 31, %Assertion.
0 = NumVars bsr 31, %Assertion.

Contents = <<?BEAM_DEBUG_INFO_VERSION:32,
NumItems:32,
Expand Down

0 comments on commit 4561f98

Please sign in to comment.