From 715cd95ae4c0bd4808b56bc27106a17b6a1f43d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 3 Sep 2024 05:52:05 +0200 Subject: [PATCH] Teach the BEAM loader to load debug information --- erts/emulator/beam/beam_file.c | 151 +++++++++++++++++++++++++++++++++ erts/emulator/beam/beam_file.h | 3 +- erts/emulator/beam/beam_load.c | 2 + 3 files changed, 155 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/beam_file.c b/erts/emulator/beam/beam_file.c index ccb37c4fa50b..3274ca90858e 100644 --- a/erts/emulator/beam/beam_file.c +++ b/erts/emulator/beam/beam_file.c @@ -654,6 +654,148 @@ 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; + int i; + BeamOpAllocator op_allocator; + BeamCodeReader *op_reader; + BeamOp* op = NULL; + + LoadAssert(beamreader_read_i32(p_reader, &count)); + LoadAssert(beamreader_read_i32(p_reader, &num_vars)); + + erts_printf("DbgB: %T: %d %d\n", beam->module, count, num_vars); + + beamopallocator_init(&op_allocator); + + op_reader = erts_alloc(ERTS_ALC_T_PREPARED_CODE, sizeof(BeamCodeReader)); + + op_reader->allocator = &op_allocator; + op_reader->file = beam; + op_reader->pending = NULL; + op_reader->first = 1; + op_reader->reader = *p_reader; + + for (i = 0; i < count; i++) { + BeamOpArg *arg; + int extra_args; + + if (!beamcodereader_next(op_reader, &op)) { + goto error; + } + if (op->op != genop_call_2) { + goto error; + } + + arg = op->a; + + switch (arg->type) { + case TAG_n: + erts_printf("%d: no stack frame\n", i + 1); + break; + case TAG_u: + erts_printf("%d: %u\n", i + 1, op->a[0].val); + break; + default: + goto error; + } + + arg++; + + if (arg->type != TAG_u) { + goto error; + } + extra_args = arg->val; + + arg++; + + 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; + } + ERTS_GET_BITSTRING(var_name, base, offset, size); + if (offset != 0 || size % 8 != 0) { + goto error; + } + + erts_printf(" %.*s ", size / 8, base); + + switch (arg[1].type) { + case TAG_i: + erts_printf("%ld", arg[1].val); + break; + case TAG_a: + erts_printf("%T", arg[1].val); + break; + case TAG_x: + erts_printf("{x,%ld}", arg[1].val); + break; + case TAG_y: + erts_printf("{y,%ld}", arg[1].val); + break; + case TAG_q: + erts_printf("%T", beamfile_get_literal(beam, arg[1].val)); + break; + default: + goto error; + } + + erts_printf("\n"); + + arg += 2; + extra_args -= 2; + } + + if (extra_args < 0) { + goto error; + } + + erts_printf("\n"); + + beamopallocator_free_op(&op_allocator, op); + } + + beamcodereader_close(op_reader); + beamopallocator_dtor(&op_allocator); + + return 1; + + error: + if (op != NULL) { + beamopallocator_free_op(&op_allocator, op); + } + beamcodereader_close(op_reader); + beamopallocator_dtor(&op_allocator); + return 0; +} + +static int parse_debug_chunk(BeamFile *beam, IFF_Chunk *chunk) { + BeamReader reader; + Sint32 version; + + beamreader_init(chunk->data, chunk->size, &reader); + + LoadAssert(beamreader_read_i32(&reader, &version)); + + if (version == 0) { + return parse_debug_chunk_data(beam, &reader); + } else { + /* Silently ignore chunk of wrong version. */ + return 1; + } +} + static ErlHeapFragment *new_literal_fragment(Uint size) { ErlHeapFragment *bp; @@ -898,6 +1040,7 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { MakeIffId('A', 't', 'o', 'm'), /* 11 */ MakeIffId('T', 'y', 'p', 'e'), /* 12 */ MakeIffId('M', 'e', 't', 'a'), /* 13 */ + MakeIffId('D', 'b', 'g', 'B'), /* 14 */ }; static const int UTF8_ATOM_CHUNK = 0; @@ -916,6 +1059,7 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { static const int OBSOLETE_ATOM_CHUNK = 11; static const int TYPE_CHUNK = 12; static const int META_CHUNK = 13; + static const int DEBUG_CHUNK = 14; static const int NUM_CHUNKS = sizeof(chunk_iffs) / sizeof(chunk_iffs[0]); @@ -1013,6 +1157,13 @@ beamfile_read(const byte *data, size_t size, BeamFile *beam) { init_fallback_type_table(beam); } + if (chunks[DEBUG_CHUNK].size > 0) { + if (!parse_debug_chunk(beam, &chunks[DEBUG_CHUNK])) { + error = BEAMFILE_READ_CORRUPT_DEBUG_TABLE; + goto error; + } + } + beam->strings.data = chunks[STR_CHUNK].data; beam->strings.size = chunks[STR_CHUNK].size; diff --git a/erts/emulator/beam/beam_file.h b/erts/emulator/beam/beam_file.h index f32f9db2670e..60cf6dfd510a 100644 --- a/erts/emulator/beam/beam_file.h +++ b/erts/emulator/beam/beam_file.h @@ -206,7 +206,8 @@ enum beamfile_read_result { BEAMFILE_READ_CORRUPT_LAMBDA_TABLE, BEAMFILE_READ_CORRUPT_LINE_TABLE, BEAMFILE_READ_CORRUPT_LITERAL_TABLE, - BEAMFILE_READ_CORRUPT_TYPE_TABLE + BEAMFILE_READ_CORRUPT_TYPE_TABLE, + BEAMFILE_READ_CORRUPT_DEBUG_TABLE }; typedef struct { diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index ad75509bc4c7..fdf285c5eb1d 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -170,6 +170,8 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, BeamLoadError0(stp, "corrupt locals table"); case BEAMFILE_READ_CORRUPT_TYPE_TABLE: BeamLoadError0(stp, "corrupt type table"); + case BEAMFILE_READ_CORRUPT_DEBUG_TABLE: + BeamLoadError0(stp, "corrupt BEAM debug information table"); case BEAMFILE_READ_SUCCESS: break; }