From 46fb5cdb8306aafe8c59fa2e15ab7bbc67b59356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 19 Mar 2021 14:18:12 +0100 Subject: [PATCH 1/5] Add new Line Data Structure --- librz/bin/dbginfo.c | 192 +++++++++++++++++ librz/include/rz_bin.h | 80 ++++++- test/unit/meson.build | 1 + test/unit/test_bin_lines.c | 430 +++++++++++++++++++++++++++++++++++++ 4 files changed, 702 insertions(+), 1 deletion(-) create mode 100644 test/unit/test_bin_lines.c diff --git a/librz/bin/dbginfo.c b/librz/bin/dbginfo.c index 02f172b7b7c..7860ca719e6 100644 --- a/librz/bin/dbginfo.c +++ b/librz/bin/dbginfo.c @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: 2009-2020 nibble // SPDX-FileCopyrightText: 2009-2020 pancake +// SPDX-FileCopyrightText: 2021 thestr4ng3r // SPDX-License-Identifier: LGPL-3.0-only #include @@ -13,6 +14,197 @@ RZ_API void rz_bin_source_row_free(RzBinSourceRow *row) { free(row); } +RZ_API void rz_bin_source_line_info_builder_init(RzBinSourceLineInfoBuilder *builder) { + rz_vector_init(&builder->samples, sizeof(RzBinSourceLineSample), NULL, NULL); + rz_str_constpool_init(&builder->filename_pool); +} + +RZ_API void rz_bin_source_line_info_builder_fini(RzBinSourceLineInfoBuilder *builder) { + rz_vector_fini(&builder->samples); + rz_str_constpool_fini(&builder->filename_pool); +} + +/** + * \brief Push a new sample into the builder + * + * This function is used to continuously fill the builder with concrete samples of line info for a specific address, + * usually during parsing of debug info from a file. + * The samples may be pushed in any order and the builder will later take care of generating a valid RzBinSourceLineInfo from it. + * + * \param line may be 0 or a positive line number, where 0 means that this entry closes the one before it. see also RzBinSourceLine. + */ +RZ_API void rz_bin_source_line_info_builder_push_sample(RzBinSourceLineInfoBuilder *builder, ut64 address, ut32 line, ut32 column, const char *file) { + RzBinSourceLineSample *sample = rz_vector_push(&builder->samples, NULL); + if (!sample) { + return; + } + sample->address = address; + sample->line = line; + sample->column = column; + sample->file = file ? rz_str_constpool_get(&builder->filename_pool, file) : NULL; +} + +static int line_sample_cmp(const void *a, const void *b) { + const RzBinSourceLineSample *sa = a; + const RzBinSourceLineSample *sb = b; + // first, sort by addr + if (sa->address < sb->address) { + return -1; + } + if (sa->address > sb->address) { + return 1; + } + // closing samples are always equal (rest of their fields are ignored anyway) + if (rz_bin_source_line_sample_is_closing(sa) && rz_bin_source_line_sample_is_closing(sb)) { + return 0; + } + // push closing samples to the back, which is necessary to skip them during packing + if (rz_bin_source_line_sample_is_closing(sa)) { + return 1; + } + if (rz_bin_source_line_sample_is_closing(sb)) { + return -1; + } + // then sort by line + if (sa->line < sb->line) { + return -1; + } + if (sa->line > sb->line) { + return 1; + } + // then by column + if (sa->column < sb->column) { + return -1; + } + if (sa->column > sb->column) { + return 1; + } + // and eventually by file because this is the most exponsive operation + if (!sa->file && !sb->file) { + return 0; + } + if (!sa->file) { + return -1; + } + if (!sb->file) { + return 1; + } + return strcmp(sa->file, sb->file); +} + +RZ_API RzBinSourceLineInfo *rz_bin_source_line_info_builder_build_and_fini(RzBinSourceLineInfoBuilder *builder) { + RzBinSourceLineInfo *r = RZ_NEW0(RzBinSourceLineInfo); + if (!r) { + goto err; + } + size_t initial_samples_count = rz_vector_len(&builder->samples); // final count may be less after removing unnecessary closing samples + if (initial_samples_count) { + r->samples = RZ_NEWS0(RzBinSourceLineSample, initial_samples_count); + if (!r->samples) { + goto err_r; + } + + // samples should be built in flat RzVector to avoid excessive small mallocs, + // for sorting we use a pvector with references into our flat vectors (after flushing them). + + RzPVector sorter; + rz_pvector_init(&sorter, NULL); + RzBinSourceLineSample *initial_samples = rz_vector_flush(&builder->samples); + rz_pvector_reserve(&sorter, initial_samples_count); + for (size_t i = 0; i < initial_samples_count; i++) { + rz_pvector_push(&sorter, &initial_samples[i]); + } + rz_pvector_sort(&sorter, line_sample_cmp); + + r->samples_count = 0; + for (size_t i = 0; i < initial_samples_count; i++) { + RzBinSourceLineSample *new_sample = rz_pvector_at(&sorter, i); + if (r->samples_count) { + RzBinSourceLineSample *prev = &r->samples[r->samples_count - 1]; + if (prev->address == new_sample->address && rz_bin_source_line_sample_is_closing(new_sample)) { + // closing sample but there are others that are not closing so this is dropped + continue; + } + } + r->samples[r->samples_count++] = *new_sample; + } + free(initial_samples); // all inner strings are moved already + rz_pvector_fini(&sorter); + } + r->filename_pool = builder->filename_pool; + // don't call regular fini on the builder because we moved its string pool! + rz_vector_fini(&builder->samples); + return r; +err_r: + free(r); +err: + rz_bin_source_line_info_builder_fini(builder); + return NULL; +} + +RZ_API void rz_bin_source_line_info_free(RzBinSourceLineInfo *sli) { + if (!sli) { + return; + } + free(sli->samples); + rz_str_constpool_fini(&sli->filename_pool); + free(sli); +} + +/** + * \brief Find the first sample that affects the given address. + * i.e. find the first sample with the highest address less or equal to addr. + * There may be more which can be retrieved by repeatedly calling rz_bin_source_line_info_get_next() until it returns NULL. + */ +RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_first_at(const RzBinSourceLineInfo *sli, ut64 addr) { + if (!sli->samples_count) { + return NULL; + } + // binary search + size_t l = 0; + size_t h = sli->samples_count; + while (l < h - 1) { + size_t m = l + ((h - l) >> 1); + if (addr < sli->samples[m].address) { + h = m; + } else { + l = m; + } + } + if (l >= sli->samples_count) { + return NULL; + } + RzBinSourceLineSample *r = &sli->samples[l]; + if (r->address > addr || rz_bin_source_line_sample_is_closing(r)) { + return NULL; + } + // walk back to the very first entry with this addr + while (r > sli->samples) { + if ((r - 1)->address == r->address) { + r--; + } else { + break; + } + } + return r; +} + +/** + * \param cur MUST be a pointer returned by either rz_bin_source_line_info_get_first_at() or rz_bin_source_line_info_get_next(). + * \return The next sample at the same address as cur or NULL if there is none. + */ +RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_next(const RzBinSourceLineInfo *sli, RZ_NONNULL const RzBinSourceLineSample *cur) { + rz_return_val_if_fail(sli && cur && cur >= sli->samples && cur < sli->samples + sli->samples_count, NULL); + if (cur == sli->samples + sli->samples_count - 1) { + return NULL; + } + const RzBinSourceLineSample *next = cur + 1; + if (next->address != cur->address) { + return NULL; + } + return next; +} + RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *line) { rz_return_val_if_fail(bin, false); RzBinFile *binfile = rz_bin_cur(bin); diff --git a/librz/include/rz_bin.h b/librz/include/rz_bin.h index 73dd0b892eb..722d005d1c1 100644 --- a/librz/include/rz_bin.h +++ b/librz/include/rz_bin.h @@ -9,6 +9,7 @@ typedef struct rz_bin_t RzBin; typedef struct rz_bin_file_t RzBinFile; +typedef struct rz_bin_source_line_info_t RzBinSourceLineInfo; #include #include @@ -421,6 +422,84 @@ typedef struct rz_bin_trycatch_t { RZ_API RzBinTrycatch *rz_bin_trycatch_new(ut64 source, ut64 from, ut64 to, ut64 handler, ut64 filter); RZ_API void rz_bin_trycatch_free(RzBinTrycatch *tc); +/** + * \brief A single sample of source line info for a specific address + * + * If at least one of the line, column and file members is not 0/NULL, such a sample specifies the line info + * for all addresses greater or equal to address until the next address that has another sample. + * + * If all the members line, column and file are 0/NULL, then this is a closing sample, indicating that the + * previous entry stops here. The address is the first address **not contained** by the previous record. + * Such a case corresponds for example to what DW_LNE_end_sequence emits in Dwarf. + * Use rz_bin_source_line_sample_is_closing() for checking if a sample is closing. + */ +typedef struct rz_bin_source_line_sample_t { + /** + * The first address that is covered by the given line and column, + * or, if all other members are 0/NULL, this is the first. + */ + ut64 address; + + /** + * If > 0, then indicates the line for the given address and the following. + * If == 0, then indicates that no line information is known. + * + * 32bit for this value is an intentional decision to lower memory consumption. + */ + ut32 line; + + /** + * If > 0, then indicates the column. + * If == 0, then no column information is known. + * + * 32bit for this value is an intentional decision to lower memory consumption. + */ + ut32 column; + + /** + * Filename, which must come out of the const pool of the owning + * RzBinSourceLineInfo or RzBinSourceLineInfoBuilder. + */ + const char *file; +} RzBinSourceLineSample; + +/* + * see documentation of RzBinSourceLineSample about what closing exactly means. + */ +static inline bool rz_bin_source_line_sample_is_closing(const RzBinSourceLineSample *s) { + return !s->line && !s->column && !s->file; +} + +struct rz_bin_source_line_info_t { + /** + * \brief All source line references for given adresses + * + * These elements must be sorted by address and addresses must be unique, so binary search can be applied. + * Source file information is not contained within this array because source file changes + * are generally much sparser than line changes. + */ + RzBinSourceLineSample *samples; + size_t samples_count; + RzStrConstPool filename_pool; +}; // RzBinSourceLineInfo + +/** + * Temporary data structure for building an RzBinSourceLineInfo. + */ +typedef struct rz_bin_source_line_info_builder_t { + RzVector /**/ samples; //< may be unsorted and will be sorted in the finalization step + RzStrConstPool filename_pool; +} RzBinSourceLineInfoBuilder; + +RZ_API void rz_bin_source_line_info_builder_init(RzBinSourceLineInfoBuilder *builder); +RZ_API void rz_bin_source_line_info_builder_fini(RzBinSourceLineInfoBuilder *builder); +RZ_API void rz_bin_source_line_info_builder_push_sample(RzBinSourceLineInfoBuilder *builder, ut64 address, ut32 line, ut32 column, const char *file); +RZ_API RzBinSourceLineInfo *rz_bin_source_line_info_builder_build_and_fini(RzBinSourceLineInfoBuilder *builder); + +RZ_API void rz_bin_source_line_info_free(RzBinSourceLineInfo *sli); +RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_first_at(const RzBinSourceLineInfo *sli, ut64 addr); +RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_next(const RzBinSourceLineInfo *sli, RZ_NONNULL const RzBinSourceLineSample *cur); + typedef struct { /** * The first address that is covered by the given line and column, @@ -443,7 +522,6 @@ typedef struct { */ unsigned int column; } RzBinSourceRow; - RZ_API void rz_bin_source_row_free(RzBinSourceRow *row); typedef struct rz_bin_plugin_t { diff --git a/test/unit/meson.build b/test/unit/meson.build index 44961a1c0ff..d8ad489d7d0 100644 --- a/test/unit/meson.build +++ b/test/unit/meson.build @@ -19,6 +19,7 @@ if get_option('enable_tests') 'base64', 'big', 'bin', + 'bin_lines', 'binheap', 'bitmap', 'buf', diff --git a/test/unit/test_bin_lines.c b/test/unit/test_bin_lines.c new file mode 100644 index 00000000000..74cd7081a2c --- /dev/null +++ b/test/unit/test_bin_lines.c @@ -0,0 +1,430 @@ +// SPDX-FileCopyrightText: 2021 thestr4ng3r +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "minunit.h" + +bool test_source_line_info_builder_empty() { + RzBinSourceLineInfoBuilder bob; + rz_bin_source_line_info_builder_init(&bob); + // add nothing + RzBinSourceLineInfo *li = rz_bin_source_line_info_builder_build_and_fini(&bob); + mu_assert_eq(li->samples_count, 0, "samples count"); + mu_assert_null(li->samples, "samples"); + const RzBinSourceLineSample *sample = rz_bin_source_line_info_get_first_at(li, 0x42); + mu_assert_null(sample, "no sample"); + rz_bin_source_line_info_free(li); + mu_end; +} + +bool test_source_line_info_builder() { +#define FUZZ_COUNT 200 + for (size_t f = 0; f < FUZZ_COUNT; f++) { +#undef FUZZ_COUNT + RzBinSourceLineInfoBuilder bob; + rz_bin_source_line_info_builder_init(&bob); + + // push the samples in random orders +#define SAMPLES_COUNT 15 + bool samples_applied[SAMPLES_COUNT] = { 0 }; + for (size_t i = 0; i < SAMPLES_COUNT; i++) { + size_t j = rand() % SAMPLES_COUNT; + while (samples_applied[j]) { + j = (j + 1) % SAMPLES_COUNT; + } +#undef SAMPLES_COUNT + samples_applied[j] = true; + switch (j) { + case 0: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1000, 42, 3, "mayan.c"); + break; + case 1: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1001, 0, 5, "mayan.c"); + break; + case 2: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1001, 1337, 1, "mayan.c"); + break; + case 3: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1002, 123, 2, "mayan.c"); + break; + case 4: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1002, 34, 123, "panoramas.c"); + break; + case 5: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1005, 0, 0, NULL); + break; + case 6: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1005, 23, 0, "mayan.c"); + break; + case 7: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1010, 0, 0, NULL); + break; + case 8: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1010, 10, 100, NULL); + break; + case 9: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1010, 10, 23, "panoramas.c"); + break; + case 10: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1020, 4, 71, "pyramid.c"); + break; + case 11: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1020, 23, 12, "pyjamas.c"); + break; + case 12: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1080, 0, 0, NULL); + break; + case 13: + rz_bin_source_line_info_builder_push_sample(&bob, 0x1090, 0, 0, NULL); + break; + case 14: + rz_bin_source_line_info_builder_push_sample(&bob, 0x2000, 52, 17, "pyramania.c"); + break; + default: + break; + } + } + + RzBinSourceLineInfo *li = rz_bin_source_line_info_builder_build_and_fini(&bob); + + static const RzBinSourceLineSample samples_expected[] = { + { 0x1000, 42, 3, "mayan.c" }, + { 0x1001, 0, 5, "mayan.c" }, + { 0x1001, 1337, 1, "mayan.c" }, + { 0x1002, 34, 123, "panoramas.c" }, + { 0x1002, 123, 2, "mayan.c" }, + { 0x1005, 23, 0, "mayan.c" }, + { 0x1010, 10, 23, "panoramas.c" }, + { 0x1010, 10, 100, NULL }, + { 0x1020, 4, 71, "pyramid.c" }, + { 0x1020, 23, 12, "pyjamas.c" }, + { 0x1080, 0, 0, NULL }, + { 0x1090, 0, 0, NULL }, + { 0x2000, 52, 17, "pyramania.c" } + }; + + mu_assert_eq(li->samples_count, RZ_ARRAY_SIZE(samples_expected), "samples count"); + for (size_t i = 0; i < RZ_ARRAY_SIZE(samples_expected); i++) { + const RzBinSourceLineSample *a = &li->samples[i]; + const RzBinSourceLineSample *e = &samples_expected[i]; + mu_assert_eq(a->address, e->address, "sample address"); + if (e->line) { + mu_assert_eq(a->line, e->line, "sample line"); + mu_assert_eq(a->column, e->column, "sample column"); + if (e->file) { + mu_assert_notnull(a->file, "sample file"); + mu_assert_streq(a->file, e->file, "sample file"); + } else { + mu_assert_null(a->file, "sample file"); + } + } else { + mu_assert_eq(a->line, 0, "closing line"); + // rest of closing entries is irrelevant + } + } + + rz_bin_source_line_info_free(li); + } + mu_end; +} + +bool test_source_line_info_builder_fuzz() { + const char *const test_filenames[] = { + "into.c", + "the.c", + "black.c", + "wide.c", + "open.c" + }; + +#define FUZZ_COUNT 200 + for (size_t f = 0; f < FUZZ_COUNT; f++) { +#undef FUZZ_COUNT + RzBinSourceLineInfoBuilder bob; + rz_bin_source_line_info_builder_init(&bob); + + // generate a lot of random samples and check them against a + // super slow but super simple equivalent algorithm +#define SAMPLES_COUNT 0x200 + RzBinSourceLineSample samples[SAMPLES_COUNT] = { 0 }; + for (size_t i = 0; i < SAMPLES_COUNT; i++) { + samples[i].address = rand() % 0x100; + if (rand() % 10 > 2) { + // non-closing entry + samples[i].line = rand() % 16; + samples[i].column = rand() % 16; + samples[i].file = rand() % 10 == 0 ? NULL : test_filenames[rand() % RZ_ARRAY_SIZE(test_filenames)]; + } + rz_bin_source_line_info_builder_push_sample(&bob, samples[i].address, samples[i].line, samples[i].column, samples[i].file); + } + RzBinSourceLineInfo *li = rz_bin_source_line_info_builder_build_and_fini(&bob); + + // every original sample must be correctly represented in the result... + for (size_t i = 0; i < SAMPLES_COUNT; i++) { + RzBinSourceLineSample *s = &samples[i]; + if (rz_bin_source_line_sample_is_closing(s)) { + for (size_t j = 0; j < SAMPLES_COUNT; j++) { + if (j == i) { + continue; + } + if (samples[j].address == s->address && !rz_bin_source_line_sample_is_closing(&samples[j])) { + // ...unless the sample is a closing one and overwritten by a + // non-closing one at the same address, in which case there must be only + // non-closing samples at this address in the result. + for (size_t k = 0; k < li->samples_count; k++) { + RzBinSourceLineSample *a = &li->samples[k]; + if (a->address > s->address) { + // nothing interesting after here + break; + } + if (a->address < s->address) { + // not there yet + continue; + } + mu_assert_true(!rz_bin_source_line_sample_is_closing(a), "closing sample override"); + } + goto skip; + } + } + } + const RzBinSourceLineSample *a = rz_bin_source_line_info_get_first_at(li, s->address); + if (rz_bin_source_line_sample_is_closing(s)) { + mu_assert_null(a, "result sample for original closing sample"); + continue; + } + while (true) { + mu_assert_notnull(a, "result sample for original sample"); + mu_assert_eq(a->address, s->address, "result sample addr"); + if (a->line == s->line && a->column == s->column && + ((!a->file && !s->file) || (a->file && s->file && !strcmp(a->file, s->file)))) { + // found it! + break; + } + a = rz_bin_source_line_info_get_next(li, a); + } + skip: + continue; + } + + // every resulting sample must be the equivalent of some original sample + for (size_t i = 0; i < li->samples_count; i++) { + RzBinSourceLineSample *a = &li->samples[i]; + if (i) { + // little side-check that everything is sorted + mu_assert_true(li->samples[i - 1].address <= a->address, "increasing chain"); + } + bool found = false; + for (size_t j = 0; j < SAMPLES_COUNT; j++) { + RzBinSourceLineSample *s = &samples[j]; + if (a->address == s->address && + ((rz_bin_source_line_sample_is_closing(a) && rz_bin_source_line_sample_is_closing(s)) || (a->line == s->line && a->column == s->column && ((!a->file && !s->file) || (a->file && s->file && !strcmp(a->file, s->file)))))) { + found = true; + break; + } + } + mu_assert_true(found, "original sample for result sample"); + } + + rz_bin_source_line_info_free(li); + } +#undef SAMPLES_COUNT + mu_end; +} + +bool test_source_line_info_query() { + static const RzBinSourceLineSample samples[] = { + { 0x1000, 42, 3, "mayan.c" }, + { 0x1001, 0, 5, "mayan.c" }, + { 0x1001, 1337, 1, "mayan.c" }, + { 0x1002, 34, 123, "panoramas.c" }, + { 0x1002, 123, 2, "mayan.c" }, + { 0x1005, 23, 0, "mayan.c" }, + { 0x1010, 10, 23, "panoramas.c" }, + { 0x1010, 10, 100, NULL }, + { 0x1020, 4, 71, "pyramid.c" }, + { 0x1020, 23, 12, "pyjamas.c" }, + { 0x1080, 0, 0, NULL }, + { 0x1090, 0, 0, NULL }, + { 0x2000, 52, 17, "pyramania.c" } + }; + + RzBinSourceLineInfo *li = RZ_NEW0(RzBinSourceLineInfo); + li->samples = rz_mem_dup(samples, sizeof(samples)); + li->samples_count = RZ_ARRAY_SIZE(samples); + rz_str_constpool_init(&li->filename_pool); + for (size_t i = 0; i < RZ_ARRAY_SIZE(samples); i++) { + if (li->samples[i].file) { + li->samples[i].file = rz_str_constpool_get(&li->filename_pool, li->samples[i].file); + } + } + + const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(li, 0); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0xfff); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1000); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1000, "sample addr"); + mu_assert_eq(s->line, 42, "sample line"); + mu_assert_eq(s->column, 3, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1001); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1001, "sample addr"); + mu_assert_eq(s->line, 0, "sample line"); + mu_assert_eq(s->column, 5, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1001, "sample addr"); + mu_assert_eq(s->line, 1337, "sample line"); + mu_assert_eq(s->column, 1, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1002); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 34, "sample line"); + mu_assert_eq(s->column, 123, "sample column"); + mu_assert_streq(s->file, "panoramas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 123, "sample line"); + mu_assert_eq(s->column, 2, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1003); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 34, "sample line"); + mu_assert_eq(s->column, 123, "sample column"); + mu_assert_streq(s->file, "panoramas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 123, "sample line"); + mu_assert_eq(s->column, 2, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1004); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 34, "sample line"); + mu_assert_eq(s->column, 123, "sample column"); + mu_assert_streq(s->file, "panoramas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1002, "sample addr"); + mu_assert_eq(s->line, 123, "sample line"); + mu_assert_eq(s->column, 2, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1005); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1005, "sample addr"); + mu_assert_eq(s->line, 23, "sample line"); + mu_assert_eq(s->column, 0, "sample column"); + mu_assert_streq(s->file, "mayan.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1011); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1010, "sample addr"); + mu_assert_eq(s->line, 10, "sample line"); + mu_assert_eq(s->column, 23, "sample column"); + mu_assert_streq(s->file, "panoramas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1010, "sample addr"); + mu_assert_eq(s->line, 10, "sample line"); + mu_assert_eq(s->column, 100, "sample column"); + mu_assert_null(s->file, "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1020); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1020, "sample addr"); + mu_assert_eq(s->line, 4, "sample line"); + mu_assert_eq(s->column, 71, "sample column"); + mu_assert_streq(s->file, "pyramid.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1020, "sample addr"); + mu_assert_eq(s->line, 23, "sample line"); + mu_assert_eq(s->column, 12, "sample column"); + mu_assert_streq(s->file, "pyjamas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x107f); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1020, "sample addr"); + mu_assert_eq(s->line, 4, "sample line"); + mu_assert_eq(s->column, 71, "sample column"); + mu_assert_streq(s->file, "pyramid.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x1020, "sample addr"); + mu_assert_eq(s->line, 23, "sample line"); + mu_assert_eq(s->column, 12, "sample column"); + mu_assert_streq(s->file, "pyjamas.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x1080); + mu_assert_null(s, "sample"); + s = rz_bin_source_line_info_get_first_at(li, 0x1081); + mu_assert_null(s, "sample"); + s = rz_bin_source_line_info_get_first_at(li, 0x1090); + mu_assert_null(s, "sample"); + s = rz_bin_source_line_info_get_first_at(li, 0x1fff); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x2000); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x2000, "sample addr"); + mu_assert_eq(s->line, 52, "sample line"); + mu_assert_eq(s->column, 17, "sample column"); + mu_assert_streq(s->file, "pyramania.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + s = rz_bin_source_line_info_get_first_at(li, 0x500000); + mu_assert_notnull(s, "sample"); + mu_assert_eq(s->address, 0x2000, "sample addr"); + mu_assert_eq(s->line, 52, "sample line"); + mu_assert_eq(s->column, 17, "sample column"); + mu_assert_streq(s->file, "pyramania.c", "sample file"); + s = rz_bin_source_line_info_get_next(li, s); + mu_assert_null(s, "sample"); + + rz_bin_source_line_info_free(li); + mu_end; +} + +bool all_tests() { + srand(time(0)); + mu_run_test(test_source_line_info_builder_empty); + mu_run_test(test_source_line_info_builder); + mu_run_test(test_source_line_info_builder_fuzz); + mu_run_test(test_source_line_info_query); + return tests_passed != tests_run; +} + +mu_main(all_tests) From 1b3869e0e033f0dc18eafaf8886fe8cfad8ed8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 22 Mar 2021 20:14:39 +0100 Subject: [PATCH 2/5] Make Dwarf emit RzBinSourceLineInfo --- librz/bin/dwarf.c | 184 +++-- librz/core/cbin.c | 24 +- librz/core/cdwarf.c | 54 +- librz/include/rz_bin_dwarf.h | 24 +- librz/include/rz_core.h | 2 +- test/db/abi/compilers/clang | 2 +- test/db/abi/compilers/clang_64 | 2 +- test/db/abi/compilers/gcc | 2 +- test/db/abi/compilers/gcc_64 | 2 +- test/db/cmd/dwarf | 42 +- test/db/formats/mangling/bin | 2 +- test/db/tools/rz_bin | 2 +- test/unit/test_dwarf.c | 1279 +++++++++++++++++++++----------- 13 files changed, 1060 insertions(+), 561 deletions(-) diff --git a/librz/bin/dwarf.c b/librz/bin/dwarf.c index ce882817f3b..816b255ba36 100644 --- a/librz/bin/dwarf.c +++ b/librz/bin/dwarf.c @@ -544,13 +544,13 @@ static const ut8 *parse_line_header_source(RzBinFile *bf, const ut8 *buf, const /** * \param info if not NULL, filenames can get resolved to absolute paths using the compilation unit dirs from it */ -RZ_API char *rz_bin_dwarf_line_header_get_full_file_path(RZ_NULLABLE RzBinDwarfDebugInfo *info, const RzBinDwarfLineHeader *header, ut64 file_index) { +RZ_API char *rz_bin_dwarf_line_header_get_full_file_path(RZ_NULLABLE const RzBinDwarfDebugInfo *info, const RzBinDwarfLineHeader *header, ut64 file_index) { rz_return_val_if_fail(header, NULL); if (file_index >= header->file_names_count) { return NULL; } RzBinDwarfLineFileEntry *file = &header->file_names[file_index]; - if (!file) { + if (!file->name) { return NULL; } @@ -582,6 +582,34 @@ RZ_API char *rz_bin_dwarf_line_header_get_full_file_path(RZ_NULLABLE RzBinDwarfD return r; } +RZ_API RzBinDwarfLineFileCache rz_bin_dwarf_line_header_new_file_cache(const RzBinDwarfLineHeader *hdr) { + return RZ_NEWS0(char *, hdr->file_names_count); +} + +RZ_API void rz_bin_dwarf_line_header_free_file_cache(const RzBinDwarfLineHeader *hdr, RzBinDwarfLineFileCache fnc) { + if (!fnc) { + return; + } + for (size_t i = 0; i < hdr->file_names_count; i++) { + free(fnc[i]); + } + free(fnc); +} + +static const char *get_full_file_path(const RzBinDwarfDebugInfo *info, const RzBinDwarfLineHeader *header, + RZ_NULLABLE RzBinDwarfLineFileCache cache, ut64 file_index) { + if (file_index >= header->file_names_count) { + return NULL; + } + if (!cache) { + return header->file_names[file_index].name; + } + if (!cache[file_index]) { + cache[file_index] = rz_bin_dwarf_line_header_get_full_file_path(info, header, file_index); + } + return cache[file_index]; +} + RZ_API ut64 rz_bin_dwarf_line_header_get_adj_opcode(const RzBinDwarfLineHeader *header, ut8 opcode) { rz_return_val_if_fail(header, 0); return opcode - header->opcode_base; @@ -807,37 +835,27 @@ RZ_API void rz_bin_dwarf_line_header_reset_regs(const RzBinDwarfLineHeader *hdr, regs->isa = 0; } -static void store_line_sample(RzList /**/ *rows_out, const RzBinDwarfLineHeader *hdr, RzBinDwarfSMRegisters *regs, - RZ_NULLABLE RzBinDwarfDebugInfo *info) { - if (!regs->file) { - return; - } - ut64 fnidx = regs->file - 1; - char *full_file = rz_bin_dwarf_line_header_get_full_file_path(info, hdr, fnidx); - if (!full_file) { - return; +static void store_line_sample(RzBinSourceLineInfoBuilder *bob, const RzBinDwarfLineHeader *hdr, RzBinDwarfSMRegisters *regs, + RZ_NULLABLE RzBinDwarfDebugInfo *info, RZ_NULLABLE RzBinDwarfLineFileCache fnc) { + const char *file = NULL; + if (regs->file) { + file = get_full_file_path(info, hdr, fnc, regs->file - 1); } - RzBinSourceRow *row = RZ_NEW(RzBinSourceRow); - if (!row) { - free(full_file); - return; - } - row->address = regs->address; - row->file = full_file; - row->line = regs->line; - row->column = regs->column; - rz_list_push(rows_out, row); + rz_bin_source_line_info_builder_push_sample(bob, regs->address, (ut32)regs->line, (ut32)regs->column, file); } +/** + * \brief Execute a single line op on regs and optionally store the resulting line info in bob + */ RZ_API bool rz_bin_dwarf_line_op_run(const RzBinDwarfLineHeader *hdr, RzBinDwarfSMRegisters *regs, RzBinDwarfLineOp *op, - RZ_NULLABLE RZ_OUT RzList /**/ *rows_out, RZ_NULLABLE RzBinDwarfDebugInfo *info) { + RZ_NULLABLE RzBinSourceLineInfoBuilder *bob, RZ_NULLABLE RzBinDwarfDebugInfo *info, RZ_NULLABLE RzBinDwarfLineFileCache fnc) { rz_return_val_if_fail(hdr && regs && op, false); switch (op->type) { case RZ_BIN_DWARF_LINE_OP_TYPE_STD: switch (op->opcode) { case DW_LNS_copy: - if (rows_out) { - store_line_sample(rows_out, hdr, regs, info); + if (bob) { + store_line_sample(bob, hdr, regs, info, fnc); } regs->basic_block = DWARF_FALSE; break; @@ -882,11 +900,9 @@ RZ_API bool rz_bin_dwarf_line_op_run(const RzBinDwarfLineHeader *hdr, RzBinDwarf switch (op->opcode) { case DW_LNE_end_sequence: regs->end_sequence = DWARF_TRUE; - if (rows_out) { - // indicate that this is not a real "line" entry but that the previous one stops here. - regs->line = 0; - regs->column = 0; - store_line_sample(rows_out, hdr, regs, info); + if (bob) { + // closing entry + rz_bin_source_line_info_builder_push_sample(bob, regs->address, 0, 0, NULL); } rz_bin_dwarf_line_header_reset_regs(hdr, regs); break; @@ -905,8 +921,8 @@ RZ_API bool rz_bin_dwarf_line_op_run(const RzBinDwarfLineHeader *hdr, RzBinDwarf case RZ_BIN_DWARF_LINE_OP_TYPE_SPEC: regs->address += rz_bin_dwarf_line_header_get_spec_op_advance_pc(hdr, op->opcode); regs->line += rz_bin_dwarf_line_header_get_spec_op_advance_line(hdr, op->opcode); - if (rows_out) { - store_line_sample(rows_out, hdr, regs, info); + if (bob) { + store_line_sample(bob, hdr, regs, info, fnc); } regs->basic_block = DWARF_FALSE; regs->prologue_end = DWARF_FALSE; @@ -921,8 +937,8 @@ RZ_API bool rz_bin_dwarf_line_op_run(const RzBinDwarfLineHeader *hdr, RzBinDwarf static size_t parse_opcodes(const ut8 *obuf, size_t len, const RzBinDwarfLineHeader *hdr, RzVector *ops_out, - RzBinDwarfSMRegisters *regs, RzList *rows_out, RZ_NULLABLE RzBinDwarfDebugInfo *info, - bool big_endian, ut8 target_addr_size) { + RzBinDwarfSMRegisters *regs, RZ_NULLABLE RzBinSourceLineInfoBuilder *bob, RZ_NULLABLE RzBinDwarfDebugInfo *info, + RZ_NULLABLE RzBinDwarfLineFileCache fnc, bool big_endian, ut8 target_addr_size) { const ut8 *buf, *buf_end; ut8 opcode; @@ -947,8 +963,8 @@ static size_t parse_opcodes(const ut8 *obuf, if (!buf) { break; } - if (rows_out) { - rz_bin_dwarf_line_op_run(hdr, regs, &op, rows_out, info); + if (bob) { + rz_bin_dwarf_line_op_run(hdr, regs, &op, bob, info, fnc); } if (ops_out) { rz_vector_push(ops_out, &op); @@ -962,10 +978,24 @@ static size_t parse_opcodes(const ut8 *obuf, return (size_t)(buf - obuf); // number of bytes we've moved by } -static RzList /**/ *parse_line_raw(RzBinFile *binfile, const ut8 *obuf, +static void line_unit_free(RzBinDwarfLineUnit *unit) { + if (!unit) { + return; + } + line_header_fini(&unit->header); + if (unit->ops) { + for (size_t i = 0; i < unit->ops_count; i++) { + rz_bin_dwarf_line_op_fini(&unit->ops[i]); + } + free(unit->ops); + } + free(unit); +} + +static RzBinDwarfLineInfo *parse_line_raw(RzBinFile *binfile, const ut8 *obuf, ut64 len, RzBinDwarfLineInfoMask mask, bool big_endian, RZ_NULLABLE RzBinDwarfDebugInfo *info) { // Dwarf 3 Standard 6.2 Line Number Information - rz_return_val_if_fail(binfile && obuf, false); + rz_return_val_if_fail(binfile && obuf, NULL); const ut8 *buf = obuf; const ut8 *buf_start = buf; @@ -977,12 +1007,25 @@ static RzList /**/ *parse_line_raw(RzBinFile *binfile, const RzBinObject *o = binfile->o; ut8 target_addr_size = o && o->info && o->info->bits ? o->info->bits / 8 : 4; - RzList *r = rz_list_newf((RzListFree)rz_bin_dwarf_line_info_free); + RzBinDwarfLineInfo *li = RZ_NEW0(RzBinDwarfLineInfo); + if (!li) { + return NULL; + } + li->units = rz_list_newf((RzListFree)line_unit_free); + if (!li->units) { + free(li); + return NULL; + } + + RzBinSourceLineInfoBuilder bob; + if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_LINES) { + rz_bin_source_line_info_builder_init(&bob); + } // each iteration we read one header AKA comp. unit while (buf <= buf_end) { - RzBinDwarfLineInfo *li = RZ_NEW0(RzBinDwarfLineInfo); - if (!li) { + RzBinDwarfLineUnit *unit = RZ_NEW0(RzBinDwarfLineUnit); + if (!unit) { break; } @@ -993,30 +1036,27 @@ static RzList /**/ *parse_line_raw(RzBinFile *binfile, const buf_size = buf_end - buf; tmpbuf = buf; - buf = parse_line_header(binfile, buf, buf_end, &li->header, buf - buf_start, big_endian); + buf = parse_line_header(binfile, buf, buf_end, &unit->header, buf - buf_start, big_endian); if (!buf) { - rz_bin_dwarf_line_info_free(li); + line_unit_free(unit); break; } bytes_read = buf - tmpbuf; RzBinDwarfSMRegisters regs; - rz_bin_dwarf_line_header_reset_regs(&li->header, ®s); + rz_bin_dwarf_line_header_reset_regs(&unit->header, ®s); // If there is more bytes in the buffer than size of the header // It means that there has to be another header/comp.unit - if (buf_size > li->header.unit_length) { - buf_size = li->header.unit_length + (li->header.is_64bit * 8 + 4); // we dif against bytes_read, but - // unit_length doesn't account unit_length field - } - // this deals with a case that there is compilation unit with any line information - if (buf_size == bytes_read) { - rz_bin_dwarf_line_info_free(li); + buf_size = RZ_MIN(buf_size, unit->header.unit_length + (unit->header.is_64bit * 8 + 4)); // length field + rest of the unit + if (buf_size <= bytes_read) { + // no info or truncated + line_unit_free(unit); continue; } if (buf_size > (buf_end - buf) + bytes_read || buf > buf_end) { - rz_bin_dwarf_line_info_free(li); + line_unit_free(unit); break; } size_t tmp_read = 0; @@ -1025,33 +1065,41 @@ static RzList /**/ *parse_line_raw(RzBinFile *binfile, const if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_OPS) { rz_vector_init(&ops, sizeof(RzBinDwarfLineOp), NULL, NULL); } - if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_ROWS) { - li->rows = rz_list_newf((RzListFree)rz_bin_source_row_free); + + RzBinDwarfLineFileCache fnc = NULL; + if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_LINES) { + fnc = rz_bin_dwarf_line_header_new_file_cache(&unit->header); } // we read the whole compilation unit (that might be composed of more sequences) do { // reads one whole sequence - tmp_read = parse_opcodes(buf, buf_size - bytes_read, &li->header, + tmp_read = parse_opcodes(buf, buf_size - bytes_read, &unit->header, (mask & RZ_BIN_DWARF_LINE_INFO_MASK_OPS) ? &ops : NULL, ®s, - li->rows, info, big_endian, target_addr_size); + (mask & RZ_BIN_DWARF_LINE_INFO_MASK_LINES) ? &bob : NULL, + info, fnc, big_endian, target_addr_size); bytes_read += tmp_read; buf += tmp_read; // Move in the buffer forward } while (bytes_read < buf_size && tmp_read != 0); // if nothing is read -> error, exit + rz_bin_dwarf_line_header_free_file_cache(&unit->header, fnc); + if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_OPS) { - li->ops_count = rz_vector_len(&ops); - li->ops = rz_vector_flush(&ops); + unit->ops_count = rz_vector_len(&ops); + unit->ops = rz_vector_flush(&ops); rz_vector_fini(&ops); } if (!tmp_read) { - rz_bin_dwarf_line_info_free(li); + line_unit_free(unit); break; } - rz_list_push(r, li); + rz_list_push(li->units, unit); } - return r; + if (mask & RZ_BIN_DWARF_LINE_INFO_MASK_LINES) { + li->lines = rz_bin_source_line_info_builder_build_and_fini(&bob); + } + return li; } RZ_API void rz_bin_dwarf_arange_set_free(RzBinDwarfARangeSet *set) { @@ -1302,14 +1350,8 @@ RZ_API void rz_bin_dwarf_line_info_free(RzBinDwarfLineInfo *li) { if (!li) { return; } - line_header_fini(&li->header); - if (li->ops) { - for (size_t i = 0; i < li->ops_count; i++) { - rz_bin_dwarf_line_op_fini(&li->ops[i]); - } - free(li->ops); - } - rz_list_free(li->rows); + rz_list_free(li->units); + rz_bin_source_line_info_free(li->lines); free(li); } @@ -2084,7 +2126,7 @@ RZ_API RzBinDwarfDebugInfo *rz_bin_dwarf_parse_info(RzBinFile *binfile, RzBinDwa /** * \param info if not NULL, filenames can get resolved to absolute paths using the compilation unit dirs from it */ -RZ_API RzList *rz_bin_dwarf_parse_line(RzBinFile *binfile, RZ_NULLABLE RzBinDwarfDebugInfo *info, RzBinDwarfLineInfoMask mask) { +RZ_API RzBinDwarfLineInfo *rz_bin_dwarf_parse_line(RzBinFile *binfile, RZ_NULLABLE RzBinDwarfDebugInfo *info, RzBinDwarfLineInfoMask mask) { rz_return_val_if_fail(binfile, NULL); RzBinSection *section = getsection(binfile, "debug_line"); if (!section) { @@ -2104,9 +2146,9 @@ RZ_API RzList *rz_bin_dwarf_parse_line(RzBinFile *binfile, RZ_NULLABLE RzBinDwar return NULL; } // Actually parse the section - RzList *lines = parse_line_raw(binfile, buf, len, mask, binfile->o && binfile->o->info && binfile->o->info->big_endian, info); + RzBinDwarfLineInfo *r = parse_line_raw(binfile, buf, len, mask, binfile->o && binfile->o->info && binfile->o->info->big_endian, info); free(buf); - return lines; + return r; } RZ_API RzList /**/ *rz_bin_dwarf_parse_aranges(RzBinFile *binfile) { diff --git a/librz/core/cbin.c b/librz/core/cbin.c index d1719b71968..a3b0cf7d0de 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -1155,24 +1155,28 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { rz_list_free(aranges); } } - RzList *lines = rz_bin_dwarf_parse_line(binfile, info, - RZ_BIN_DWARF_LINE_INFO_MASK_ROWS | (mode == RZ_MODE_PRINT ? RZ_BIN_DWARF_LINE_INFO_MASK_OPS : 0)); + RzBinDwarfLineInfo *lines = rz_bin_dwarf_parse_line(binfile, info, + RZ_BIN_DWARF_LINE_INFO_MASK_LINES | (mode == RZ_MODE_PRINT ? RZ_BIN_DWARF_LINE_INFO_MASK_OPS : 0)); rz_bin_dwarf_debug_info_free(info); if (lines) { if (mode == RZ_MODE_PRINT) { - rz_core_bin_dwarf_print_lines(lines); + rz_core_bin_dwarf_print_line_units(lines->units); } // move all produced rows out list = ownlist = rz_list_newf((RzListFree)rz_bin_source_row_free); - RzListIter *it; - RzBinDwarfLineInfo *li; - rz_list_foreach (lines, it, li) { - if (!li->rows) { + for (size_t i = 0; i < lines->lines->samples_count; i++) { + const RzBinSourceLineSample *s = &lines->lines->samples[i]; + if (!s->file) { continue; } - rz_list_join(list, li->rows); - } - rz_list_free(lines); + RzBinSourceRow *row = RZ_NEW0(RzBinSourceRow); + row->address = s->address; + row->line = s->line; + row->column = s->column; + row->file = strdup(s->file); + rz_list_push(list, row); + } + rz_bin_dwarf_line_info_free(lines); } rz_bin_dwarf_debug_abbrev_free(da); diff --git a/librz/core/cdwarf.c b/librz/core/cdwarf.c index fe26e569cbd..cfa2d76ca07 100644 --- a/librz/core/cdwarf.c +++ b/librz/core/cdwarf.c @@ -337,61 +337,61 @@ static void print_line_op(RzBinDwarfLineOp *op, RzBinDwarfLineHeader *hdr, RZ_NU rz_cons_print("\n"); } -RZ_API void rz_core_bin_dwarf_print_lines(RzList /**/ *lines) { +RZ_API void rz_core_bin_dwarf_print_line_units(RzList /**/ *lines) { rz_return_if_fail(lines); rz_cons_print("Raw dump of debug contents of section .debug_line:\n\n"); RzListIter *it; - RzBinDwarfLineInfo *li; + RzBinDwarfLineUnit *unit; bool first = true; - rz_list_foreach (lines, it, li) { + rz_list_foreach (lines, it, unit) { if (first) { first = false; } else { rz_cons_print("\n"); } rz_cons_print(" Header information:\n"); - rz_cons_printf(" Length: %" PFMT64u "\n", li->header.unit_length); - rz_cons_printf(" DWARF Version: %d\n", li->header.version); - rz_cons_printf(" Header Length: %" PFMT64d "\n", li->header.header_length); - rz_cons_printf(" Minimum Instruction Length: %d\n", li->header.min_inst_len); - rz_cons_printf(" Maximum Operations per Instruction: %d\n", li->header.max_ops_per_inst); - rz_cons_printf(" Initial value of 'is_stmt': %d\n", li->header.default_is_stmt); - rz_cons_printf(" Line Base: %d\n", li->header.line_base); - rz_cons_printf(" Line Range: %d\n", li->header.line_range); - rz_cons_printf(" Opcode Base: %d\n\n", li->header.opcode_base); + rz_cons_printf(" Length: %" PFMT64u "\n", unit->header.unit_length); + rz_cons_printf(" DWARF Version: %d\n", unit->header.version); + rz_cons_printf(" Header Length: %" PFMT64d "\n", unit->header.header_length); + rz_cons_printf(" Minimum Instruction Length: %d\n", unit->header.min_inst_len); + rz_cons_printf(" Maximum Operations per Instruction: %d\n", unit->header.max_ops_per_inst); + rz_cons_printf(" Initial value of 'is_stmt': %d\n", unit->header.default_is_stmt); + rz_cons_printf(" Line Base: %d\n", unit->header.line_base); + rz_cons_printf(" Line Range: %d\n", unit->header.line_range); + rz_cons_printf(" Opcode Base: %d\n\n", unit->header.opcode_base); rz_cons_print(" Opcodes:\n"); - for (size_t i = 1; i < li->header.opcode_base; i++) { - rz_cons_printf(" Opcode %zu has %d arg\n", i, li->header.std_opcode_lengths[i - 1]); + for (size_t i = 1; i < unit->header.opcode_base; i++) { + rz_cons_printf(" Opcode %zu has %d arg\n", i, unit->header.std_opcode_lengths[i - 1]); } rz_cons_print("\n"); - if (li->header.include_dirs_count && li->header.include_dirs) { + if (unit->header.include_dirs_count && unit->header.include_dirs) { rz_cons_printf(" The Directory Table:\n"); - for (size_t i = 0; i < li->header.include_dirs_count; i++) { - rz_cons_printf(" %u %s\n", (unsigned int)i + 1, li->header.include_dirs[i]); + for (size_t i = 0; i < unit->header.include_dirs_count; i++) { + rz_cons_printf(" %u %s\n", (unsigned int)i + 1, unit->header.include_dirs[i]); } } - if (li->header.file_names_count && li->header.file_names) { + if (unit->header.file_names_count && unit->header.file_names) { rz_cons_print("\n"); rz_cons_print(" The File Name Table:\n"); rz_cons_print(" Entry Dir Time Size Name\n"); - for (size_t i = 0; i < li->header.file_names_count; i++) { - RzBinDwarfLineFileEntry *f = &li->header.file_names[i]; + for (size_t i = 0; i < unit->header.file_names_count; i++) { + RzBinDwarfLineFileEntry *f = &unit->header.file_names[i]; rz_cons_printf(" %u %" PFMT32u " %" PFMT32u " %" PFMT32u " %s\n", (unsigned int)i + 1, f->id_idx, f->mod_time, f->file_len, f->name); } rz_cons_print("\n"); } - if (li->ops_count && li->ops) { + if (unit->ops_count && unit->ops) { // also execute all ops simultaneously which gives us nice intermediate value printing RzBinDwarfSMRegisters regs; - rz_bin_dwarf_line_header_reset_regs(&li->header, ®s); + rz_bin_dwarf_line_header_reset_regs(&unit->header, ®s); rz_cons_print(" Line Number Statements:\n"); - for (size_t i = 0; i < li->ops_count; i++) { - rz_bin_dwarf_line_op_run(&li->header, ®s, &li->ops[i], NULL, NULL); + for (size_t i = 0; i < unit->ops_count; i++) { + rz_bin_dwarf_line_op_run(&unit->header, ®s, &unit->ops[i], NULL, NULL, NULL); rz_cons_print(" "); - RzBinDwarfLineOp *op = &li->ops[i]; - print_line_op(op, &li->header, ®s); - if (op->type == RZ_BIN_DWARF_LINE_OP_TYPE_EXT && op->opcode == DW_LNE_end_sequence && i + 1 < li->ops_count) { + RzBinDwarfLineOp *op = &unit->ops[i]; + print_line_op(op, &unit->header, ®s); + if (op->type == RZ_BIN_DWARF_LINE_OP_TYPE_EXT && op->opcode == DW_LNE_end_sequence && i + 1 < unit->ops_count) { // extra newline for nice sequence separation rz_cons_print("\n"); } diff --git a/librz/include/rz_bin_dwarf.h b/librz/include/rz_bin_dwarf.h index f247ac58568..80773c69e37 100644 --- a/librz/include/rz_bin_dwarf.h +++ b/librz/include/rz_bin_dwarf.h @@ -5,6 +5,8 @@ extern "C" { #endif +struct rz_bin_source_line_info_builder_t; + #define DW_EXTENDED_OPCODE 0 #define LOP_EXTENDED 1 #define LOP_DISCARD 2 @@ -875,21 +877,27 @@ typedef struct { /** * \brief DWARF 3 Standard Section 6.2 Line Number Information - * This contains the entire line info for one compilation unit. + * This contains the entire raw line info for one compilation unit. */ typedef struct { RzBinDwarfLineHeader header; size_t ops_count; RzBinDwarfLineOp *ops; +} RzBinDwarfLineUnit; - RzList *rows; +/** + * \brief Line info of all compilation units from the entire debug_line section + */ +typedef struct { + RzList /**/ *units; + struct rz_bin_source_line_info_t *lines; } RzBinDwarfLineInfo; typedef enum { RZ_BIN_DWARF_LINE_INFO_MASK_BASIC = 0x0, //< parse just the headers RZ_BIN_DWARF_LINE_INFO_MASK_OPS = 0x1, //< decode and output all instructions - RZ_BIN_DWARF_LINE_INFO_MASK_ROWS = 0x2 //< run instructions and ouput the resulting line infos + RZ_BIN_DWARF_LINE_INFO_MASK_LINES = 0x2 //< run instructions and output the resulting line infos } RzBinDwarfLineInfoMask; typedef struct rz_bin_dwarf_loc_entry_t { @@ -939,14 +947,18 @@ RZ_API void rz_bin_dwarf_loc_free(HtUP /**/ *loc_tab RZ_API void rz_bin_dwarf_debug_info_free(RzBinDwarfDebugInfo *inf); RZ_API void rz_bin_dwarf_debug_abbrev_free(RzBinDwarfDebugAbbrev *da); -RZ_API RzList *rz_bin_dwarf_parse_line(RzBinFile *binfile, RZ_NULLABLE RzBinDwarfDebugInfo *info, RzBinDwarfLineInfoMask mask); -RZ_API char *rz_bin_dwarf_line_header_get_full_file_path(RZ_NULLABLE RzBinDwarfDebugInfo *info, const RzBinDwarfLineHeader *header, ut64 file_index); +typedef char **RzBinDwarfLineFileCache; + +RZ_API RzBinDwarfLineInfo *rz_bin_dwarf_parse_line(RzBinFile *binfile, RZ_NULLABLE RzBinDwarfDebugInfo *info, RzBinDwarfLineInfoMask mask); +RZ_API char *rz_bin_dwarf_line_header_get_full_file_path(RZ_NULLABLE const RzBinDwarfDebugInfo *info, const RzBinDwarfLineHeader *header, ut64 file_index); RZ_API ut64 rz_bin_dwarf_line_header_get_adj_opcode(const RzBinDwarfLineHeader *header, ut8 opcode); RZ_API ut64 rz_bin_dwarf_line_header_get_spec_op_advance_pc(const RzBinDwarfLineHeader *header, ut8 opcode); RZ_API st64 rz_bin_dwarf_line_header_get_spec_op_advance_line(const RzBinDwarfLineHeader *header, ut8 opcode); RZ_API void rz_bin_dwarf_line_header_reset_regs(const RzBinDwarfLineHeader *hdr, RzBinDwarfSMRegisters *regs); +RZ_API RzBinDwarfLineFileCache rz_bin_dwarf_line_header_new_file_cache(const RzBinDwarfLineHeader *hdr); +RZ_API void rz_bin_dwarf_line_header_free_file_cache(const RzBinDwarfLineHeader *hdr, RzBinDwarfLineFileCache fnc); RZ_API bool rz_bin_dwarf_line_op_run(const RzBinDwarfLineHeader *hdr, RzBinDwarfSMRegisters *regs, RzBinDwarfLineOp *op, - RZ_NULLABLE RZ_OUT RzList /**/ *rows_out, RZ_NULLABLE RzBinDwarfDebugInfo *info); + RZ_NULLABLE struct rz_bin_source_line_info_builder_t *bob, RZ_NULLABLE RzBinDwarfDebugInfo *info, RZ_NULLABLE RzBinDwarfLineFileCache fnc); RZ_API void rz_bin_dwarf_line_op_fini(RzBinDwarfLineOp *op); RZ_API void rz_bin_dwarf_line_info_free(RzBinDwarfLineInfo *li); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index aa991ee5230..72d185c1f2f 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -716,7 +716,7 @@ RZ_API void rz_core_bin_dwarf_print_attr_value(const RzBinDwarfAttrValue *val); RZ_API void rz_core_bin_dwarf_print_debug_info(const RzBinDwarfDebugInfo *inf); RZ_API void rz_core_bin_dwarf_print_loc(HtUP /**/ *loc_table, int addr_size); RZ_API void rz_core_bin_dwarf_print_aranges(RzList /**/ *aranges); -RZ_API void rz_core_bin_dwarf_print_lines(RzList /**/ *lines); +RZ_API void rz_core_bin_dwarf_print_line_units(RzList /**/ *lines); // XXX - this is kinda hacky, maybe there should be a way to // refresh the bin environment without specific calls? diff --git a/test/db/abi/compilers/clang b/test/db/abi/compilers/clang index ad6589b1301..bee35ed5444 100644 --- a/test/db/abi/compilers/clang +++ b/test/db/abi/compilers/clang @@ -26,7 +26,7 @@ CMDS=<decls[i].defs[j].attr_form, expected_form, "Incorrect children flag"); +static bool check_line_samples_eq(const RzBinSourceLineInfo *actual, + size_t samples_count_expect, const RzBinSourceLineSample *samples_expect) { + mu_assert_eq(actual->samples_count, samples_count_expect, "samples count"); + if (samples_expect) { + mu_assert_notnull(actual->samples, "samples"); + for (size_t i = 0; i < samples_count_expect; i++) { + mu_assert_eq(actual->samples[i].address, samples_expect[i].address, "sample addr"); + mu_assert_eq(actual->samples[i].line, samples_expect[i].line, "sample line"); + mu_assert_eq(actual->samples[i].column, samples_expect[i].column, "sample column"); + if (samples_expect[i].file) { + mu_assert_notnull(actual->samples[i].file, "sample file"); + mu_assert_streq(actual->samples[i].file, samples_expect[i].file, "sample file"); + } else { + mu_assert_null(actual->samples[i].file, "sample file"); + } + } + } else { + mu_assert_null(actual->samples, "samples"); + } + return true; +} + +static void print_line_samples(size_t samples_count, const RzBinSourceLineSample *samples) { + printf("{\n"); + for (size_t i = 0; i < samples_count; i++) { + printf("\t{ 0x%" PFMT64x ", %" PFMT32u ", %" PFMT32u ", %s%s%s }%s\n", + samples[i].address, + samples[i].line, + samples[i].column, + samples[i].file ? "\"" : "", + samples[i].file ? samples[i].file : "NULL", + samples[i].file ? "\"" : "", + i + 1 < samples_count ? "," : ""); + } + printf("};\n"); +} + +#define assert_line_samples_eq(actual, count_expect, samples_expect) \ + do { \ + if (!check_line_samples_eq(actual, count_expect, samples_expect)) { \ + printf("---- EXPECTED:\n"); \ + print_line_samples(count_expect, samples_expect); \ + printf("---- GOT:\n"); \ + print_line_samples(actual->samples_count, actual->samples); \ + return false; \ + } \ + } while (0); + /** * @brief Tests correct parsing of abbreviations and line information of DWARF3 C binary */ @@ -113,33 +161,23 @@ bool test_dwarf3_c_basic(void) { // this should work for dwarf2 aswell } i++; - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 1, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(li->rows), 8, "rows count"); - - const RzBinSourceRow test_rows[] = { - { 0x1129, ".//main.c", 3, 1 }, - { 0x1131, ".//main.c", 6, 1 }, - { 0x1134, ".//main.c", 7, 12 }, - { 0x1140, ".//main.c", 8, 2 }, - { 0x114a, ".//main.c", 9, 6 }, - { 0x1151, ".//main.c", 10, 9 }, - { 0x1154, ".//main.c", 11, 1 }, - { 0x1156, ".//main.c", 0, 0 } + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 1, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x1129, 3, 1, ".//main.c" }, + { 0x1131, 6, 1, ".//main.c" }, + { 0x1134, 7, 12, ".//main.c" }, + { 0x1140, 8, 2, ".//main.c" }, + { 0x114a, 9, 6, ".//main.c" }, + { 0x1151, 10, 9, ".//main.c" }, + { 0x1154, 11, 1, ".//main.c" }, + { 0x1156, 0, 0, NULL } }; - i = 0; - RzBinSourceRow *row; - RzListIter *iter; - rz_list_foreach (li->rows, iter, row) { - const RzBinSourceRow *expect = &test_rows[i++]; - mu_assert_eq(row->address, expect->address, "Row addr"); - mu_assert_streq(row->file, expect->file, "Row file"); - mu_assert_eq(row->line, expect->line, "Row line"); - mu_assert_eq(row->column, expect->column, "Row column"); - } + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - rz_list_free(line_list); rz_bin_dwarf_debug_abbrev_free(da); rz_bin_free(bin); rz_io_free(io); @@ -469,87 +507,81 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell // rz_bin_dwarf_parse_aranges (core->bin, MODE); Information not stored anywhere, not testable now? - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 1, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(li->rows), 60, "rows count"); - - int test_addresses[] = { - 0x11ee, - 0x11fa, - 0x1208, - 0x120b, - 0x120c, - 0x1218, - 0x1226, - 0x1229, - 0x122a, - 0x123a, - 0x1259, - 0x125a, - 0x1266, - 0x126b, - 0x126d, - 0x126e, - 0x127e, - 0x1298, - 0x129b, - 0x129c, - 0x12ac, - 0x12c6, - 0x12c9, - 0x12ca, - 0x12da, - 0x12f9, - 0x12fa, - 0x1306, - 0x130b, - 0x130d, - 0x130e, - 0x131a, - 0x1328, - 0x132b, - 0x132c, - 0x1338, - 0x1346, - 0x1349, - 0x134a, - 0x135a, - 0x1379, - 0x137a, - 0x1386, - 0x138b, - 0x138d, - 0x1169, - 0x1176, - 0x118b, - 0x118f, - 0x11a4, - 0x11a8, - 0x11af, - 0x11bd, - 0x11c6, - 0x11c9, - 0x11d7, - 0x11e0, - 0x11e3, - 0x11e6, - 0x11ed + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 1, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x1169, 19, 12, ".//main.cpp" }, + { 0x1176, 22, 16, ".//main.cpp" }, + { 0x118b, 22, 5, ".//main.cpp" }, + { 0x118f, 23, 15, ".//main.cpp" }, + { 0x11a4, 23, 5, ".//main.cpp" }, + { 0x11a8, 24, 7, ".//main.cpp" }, + { 0x11af, 25, 20, ".//main.cpp" }, + { 0x11bd, 25, 19, ".//main.cpp" }, + { 0x11c6, 25, 10, ".//main.cpp" }, + { 0x11c9, 26, 21, ".//main.cpp" }, + { 0x11d7, 26, 20, ".//main.cpp" }, + { 0x11e0, 26, 10, ".//main.cpp" }, + { 0x11e3, 27, 10, ".//main.cpp" }, + { 0x11e6, 28, 1, ".//main.cpp" }, + { 0x11ed, 0, 0, NULL }, + { 0x11ee, 2, 3, ".//main.cpp" }, + { 0x11fa, 2, 12, ".//main.cpp" }, + { 0x1208, 2, 15, ".//main.cpp" }, + { 0x120b, 0, 0, NULL }, + { 0x120c, 3, 11, ".//main.cpp" }, + { 0x1218, 3, 21, ".//main.cpp" }, + { 0x1226, 3, 22, ".//main.cpp" }, + { 0x1229, 0, 0, NULL }, + { 0x122a, 3, 11, ".//main.cpp" }, + { 0x123a, 3, 22, ".//main.cpp" }, + { 0x1259, 0, 0, NULL }, + { 0x125a, 4, 15, ".//main.cpp" }, + { 0x1266, 4, 31, ".//main.cpp" }, + { 0x126b, 4, 34, ".//main.cpp" }, + { 0x126d, 0, 0, NULL }, + { 0x126e, 8, 3, ".//main.cpp" }, + { 0x127e, 8, 9, ".//main.cpp" }, + { 0x1298, 8, 12, ".//main.cpp" }, + { 0x129b, 0, 0, NULL }, + { 0x129c, 9, 11, ".//main.cpp" }, + { 0x12ac, 9, 18, ".//main.cpp" }, + { 0x12c6, 9, 19, ".//main.cpp" }, + { 0x12c9, 0, 0, NULL }, + { 0x12ca, 9, 11, ".//main.cpp" }, + { 0x12da, 9, 19, ".//main.cpp" }, + { 0x12f9, 0, 0, NULL }, + { 0x12fa, 10, 15, ".//main.cpp" }, + { 0x1306, 10, 31, ".//main.cpp" }, + { 0x130b, 10, 34, ".//main.cpp" }, + { 0x130d, 0, 0, NULL }, + { 0x130e, 14, 3, ".//main.cpp" }, + { 0x131a, 14, 10, ".//main.cpp" }, + { 0x1328, 14, 13, ".//main.cpp" }, + { 0x132b, 0, 0, NULL }, + { 0x132c, 15, 11, ".//main.cpp" }, + { 0x1338, 15, 19, ".//main.cpp" }, + { 0x1346, 15, 20, ".//main.cpp" }, + { 0x1349, 0, 0, NULL }, + { 0x134a, 15, 11, ".//main.cpp" }, + { 0x135a, 15, 20, ".//main.cpp" }, + { 0x1379, 0, 0, NULL }, + { 0x137a, 16, 15, ".//main.cpp" }, + { 0x1386, 16, 30, ".//main.cpp" }, + { 0x138b, 16, 33, ".//main.cpp" }, + { 0x138d, 0, 0, NULL } }; - i = 0; + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - RzBinSourceRow *row; - RzListIter *iter; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses[i++], "Line number statement address doesn't match"); - } - - rz_list_free(line_list); rz_bin_dwarf_debug_abbrev_free(da); rz_bin_free(bin); rz_io_free(io); mu_end; } + bool test_dwarf3_cpp_many_comp_units(void) { RzBin *bin = rz_bin_new(); RzIO *io = rz_io_new(); @@ -577,39 +609,79 @@ bool test_dwarf3_cpp_many_comp_units(void) { check_abbrev_children(false); check_abbrev_code(18); - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 2, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(li->rows), 17, "rows count"); - - int test_addresses[] = { - 0x118a, - 0x1196, - 0x11a4, - 0x11a8, - 0x11b8, - 0x11d8, - 0x11e4, - 0x11e9, - 0x11eb, - 0x11f7, - 0x1206, - 0x1212, - 0x1228, - 0x1228, - 0x1234, - 0x1239, - 0x123b + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 2, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x118a, 3, 3, ".//mammal.cpp" }, + { 0x1196, 3, 19, ".//mammal.cpp" }, + { 0x11a4, 3, 22, ".//mammal.cpp" }, + { 0x11a8, 3, 3, ".//mammal.cpp" }, + { 0x11b8, 3, 22, ".//mammal.cpp" }, + { 0x11d8, 4, 22, ".//mammal.cpp" }, + { 0x11e4, 4, 31, ".//mammal.cpp" }, + { 0x11e9, 4, 34, ".//mammal.cpp" }, + { 0x11eb, 10, 12, ".//mammal.cpp" }, + { 0x11f7, 10, 12, ".//mammal.cpp" }, + { 0x1206, 12, 23, ".//mammal.cpp" }, + { 0x1212, 13, 1, ".//mammal.cpp" }, + { 0x1228, 7, 6, ".//mammal.cpp" }, + { 0x1234, 7, 26, ".//mammal.cpp" }, + { 0x1239, 7, 28, ".//mammal.cpp" }, + { 0x123b, 15, 12, ".//main.cpp" }, + { 0x1248, 18, 16, ".//main.cpp" }, + { 0x125d, 18, 5, ".//main.cpp" }, + { 0x1261, 19, 15, ".//main.cpp" }, + { 0x1276, 19, 5, ".//main.cpp" }, + { 0x127a, 20, 7, ".//main.cpp" }, + { 0x1281, 21, 20, ".//main.cpp" }, + { 0x128f, 21, 19, ".//main.cpp" }, + { 0x1298, 21, 10, ".//main.cpp" }, + { 0x129b, 22, 21, ".//main.cpp" }, + { 0x12a9, 22, 20, ".//main.cpp" }, + { 0x12b2, 22, 10, ".//main.cpp" }, + { 0x12b5, 23, 23, ".//main.cpp" }, + { 0x12ba, 23, 24, ".//main.cpp" }, + { 0x12bf, 24, 1, ".//main.cpp" }, + { 0x12c6, 2, 3, ".//mammal.h" }, + { 0x12d2, 2, 12, ".//mammal.h" }, + { 0x12e0, 2, 15, ".//mammal.h" }, + { 0x12e3, 0, 0, NULL }, + { 0x12e4, 4, 3, ".//main.cpp" }, + { 0x12f4, 4, 9, ".//main.cpp" }, + { 0x130e, 4, 12, ".//main.cpp" }, + { 0x1311, 0, 0, NULL }, + { 0x1312, 5, 11, ".//main.cpp" }, + { 0x1322, 5, 18, ".//main.cpp" }, + { 0x133c, 5, 19, ".//main.cpp" }, + { 0x133f, 0, 0, NULL }, + { 0x1340, 5, 11, ".//main.cpp" }, + { 0x1350, 5, 19, ".//main.cpp" }, + { 0x136f, 0, 0, NULL }, + { 0x1370, 6, 15, ".//main.cpp" }, + { 0x137c, 6, 31, ".//main.cpp" }, + { 0x1381, 6, 34, ".//main.cpp" }, + { 0x1383, 0, 0, NULL }, + { 0x1384, 10, 3, ".//main.cpp" }, + { 0x1390, 10, 10, ".//main.cpp" }, + { 0x139e, 10, 13, ".//main.cpp" }, + { 0x13a1, 0, 0, NULL }, + { 0x13a2, 11, 11, ".//main.cpp" }, + { 0x13ae, 11, 19, ".//main.cpp" }, + { 0x13bc, 11, 20, ".//main.cpp" }, + { 0x13bf, 0, 0, NULL }, + { 0x13c0, 11, 11, ".//main.cpp" }, + { 0x13d0, 11, 20, ".//main.cpp" }, + { 0x13ef, 0, 0, NULL }, + { 0x13f0, 12, 15, ".//main.cpp" }, + { 0x13fc, 12, 30, ".//main.cpp" }, + { 0x1401, 12, 33, ".//main.cpp" }, + { 0x1403, 0, 0, NULL } }; - i = 0; - - RzBinSourceRow *row; - RzListIter *iter; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses[i++], "Line number statement address doesn't match"); - } + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - rz_list_free(line_list); rz_bin_dwarf_debug_abbrev_free(da); rz_bin_free(bin); rz_io_free(io); @@ -633,26 +705,11 @@ bool test_dwarf_cpp_empty_line_info(void) { // this should work for dwarf2 aswel // not ignoring null entries -> 755 abbrevs mu_assert_eq(da->count, 731, "Incorrect number of abbreviation"); - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 16, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0))->rows), 271, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 1))->rows), 45, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 2))->rows), 41, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 3))->rows), 4, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 4))->rows), 4, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 5))->rows), 69, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 6))->rows), 46, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 7))->rows), 36, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 9))->rows), 4, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xa))->rows), 220, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xb))->rows), 72, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xc))->rows), 155, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xd))->rows), 331, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xe))->rows), 16, "rows count"); - mu_assert_eq(rz_list_length(((RzBinDwarfLineInfo *)rz_list_get_n(line_list, 0xf))->rows), 13, "rows count"); - - const int test_addresses[] = { + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 16, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const ut64 test_addresses[] = { 0x00401000, 0x00401000, 0x00401010, @@ -677,18 +734,13 @@ bool test_dwarf_cpp_empty_line_info(void) { // this should work for dwarf2 aswel 0x00401046, 0x00401046 }; - - int i = 0; - - RzBinSourceRow *row; - RzListIter *iter; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses[i++], "row addr"); - if (i == 23) - break; + mu_assert_eq(li->lines->samples_count, 1331, "samples count"); + for (size_t i = 0; i < RZ_ARRAY_SIZE(test_addresses); i++) { + mu_assert_eq(li->lines->samples[i].address, test_addresses[i], "line addr"); } - rz_list_free(line_list); + rz_bin_dwarf_line_info_free(li); + rz_bin_dwarf_debug_abbrev_free(da); rz_io_free(io); rz_bin_free(bin); @@ -723,98 +775,79 @@ bool test_dwarf2_cpp_many_comp_units(void) { check_abbrev_children(false); check_abbrev_code(18); - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 2, "Amount of line information parse doesn't match"); - - RzBinDwarfLineInfo *li = rz_list_get_n(line_list, 0); - mu_assert_eq(rz_list_length(li->rows), 17, "rows count"); - const ut64 test_addresses0[] = { - 0x118a, - 0x1196, - 0x11a4, - 0x11a8, - 0x11b8, - 0x11d8, - 0x11e4, - 0x11e9, - 0x11eb, - 0x11f7, - 0x1206, - 0x1212, - 0x1228, - 0x1228, - 0x1234, - 0x1239, - 0x123b + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 2, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x118a, 3, 3, ".//mammal.cpp" }, + { 0x1196, 3, 19, ".//mammal.cpp" }, + { 0x11a4, 3, 22, ".//mammal.cpp" }, + { 0x11a8, 3, 3, ".//mammal.cpp" }, + { 0x11b8, 3, 22, ".//mammal.cpp" }, + { 0x11d8, 4, 22, ".//mammal.cpp" }, + { 0x11e4, 4, 31, ".//mammal.cpp" }, + { 0x11e9, 4, 34, ".//mammal.cpp" }, + { 0x11eb, 10, 12, ".//mammal.cpp" }, + { 0x11f7, 10, 12, ".//mammal.cpp" }, + { 0x1206, 12, 23, ".//mammal.cpp" }, + { 0x1212, 13, 1, ".//mammal.cpp" }, + { 0x1228, 7, 6, ".//mammal.cpp" }, + { 0x1234, 7, 26, ".//mammal.cpp" }, + { 0x1239, 7, 28, ".//mammal.cpp" }, + { 0x123b, 15, 12, ".//main.cpp" }, + { 0x1248, 18, 16, ".//main.cpp" }, + { 0x125d, 18, 5, ".//main.cpp" }, + { 0x1261, 19, 15, ".//main.cpp" }, + { 0x1276, 19, 5, ".//main.cpp" }, + { 0x127a, 20, 7, ".//main.cpp" }, + { 0x1281, 21, 20, ".//main.cpp" }, + { 0x128f, 21, 19, ".//main.cpp" }, + { 0x1298, 21, 10, ".//main.cpp" }, + { 0x129b, 22, 21, ".//main.cpp" }, + { 0x12a9, 22, 20, ".//main.cpp" }, + { 0x12b2, 22, 10, ".//main.cpp" }, + { 0x12b5, 23, 23, ".//main.cpp" }, + { 0x12ba, 23, 24, ".//main.cpp" }, + { 0x12bf, 24, 1, ".//main.cpp" }, + { 0x12c6, 2, 3, ".//mammal.h" }, + { 0x12d2, 2, 12, ".//mammal.h" }, + { 0x12e0, 2, 15, ".//mammal.h" }, + { 0x12e3, 0, 0, NULL }, + { 0x12e4, 4, 3, ".//main.cpp" }, + { 0x12f4, 4, 9, ".//main.cpp" }, + { 0x130e, 4, 12, ".//main.cpp" }, + { 0x1311, 0, 0, NULL }, + { 0x1312, 5, 11, ".//main.cpp" }, + { 0x1322, 5, 18, ".//main.cpp" }, + { 0x133c, 5, 19, ".//main.cpp" }, + { 0x133f, 0, 0, NULL }, + { 0x1340, 5, 11, ".//main.cpp" }, + { 0x1350, 5, 19, ".//main.cpp" }, + { 0x136f, 0, 0, NULL }, + { 0x1370, 6, 15, ".//main.cpp" }, + { 0x137c, 6, 31, ".//main.cpp" }, + { 0x1381, 6, 34, ".//main.cpp" }, + { 0x1383, 0, 0, NULL }, + { 0x1384, 10, 3, ".//main.cpp" }, + { 0x1390, 10, 10, ".//main.cpp" }, + { 0x139e, 10, 13, ".//main.cpp" }, + { 0x13a1, 0, 0, NULL }, + { 0x13a2, 11, 11, ".//main.cpp" }, + { 0x13ae, 11, 19, ".//main.cpp" }, + { 0x13bc, 11, 20, ".//main.cpp" }, + { 0x13bf, 0, 0, NULL }, + { 0x13c0, 11, 11, ".//main.cpp" }, + { 0x13d0, 11, 20, ".//main.cpp" }, + { 0x13ef, 0, 0, NULL }, + { 0x13f0, 12, 15, ".//main.cpp" }, + { 0x13fc, 12, 30, ".//main.cpp" }, + { 0x1401, 12, 33, ".//main.cpp" }, + { 0x1403, 0, 0, NULL } }; - RzBinSourceRow *row; - RzListIter *iter; - i = 0; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses0[i++], "row addr"); - } + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - li = rz_list_get_n(line_list, 1); - mu_assert_eq(rz_list_length(li->rows), 50, "rows count"); - const ut64 test_addresses1[] = { - 0x12c6, - 0x12d2, - 0x12e0, - 0x12e3, - 0x12e4, - 0x12f4, - 0x130e, - 0x1311, - 0x1312, - 0x1322, - 0x133c, - 0x133f, - 0x1340, - 0x1350, - 0x136f, - 0x1370, - 0x137c, - 0x1381, - 0x1383, - 0x1384, - 0x1390, - 0x139e, - 0x13a1, - 0x13a2, - 0x13ae, - 0x13bc, - 0x13bf, - 0x13c0, - 0x13d0, - 0x13ef, - 0x13f0, - 0x13fc, - 0x1401, - 0x1403, - 0x123b, - 0x1248, - 0x125d, - 0x1261, - 0x1276, - 0x127a, - 0x1281, - 0x128f, - 0x1298, - 0x129b, - 0x12a9, - 0x12b2, - 0x12b5, - 0x12ba, - 0x12bf, - 0x12c6 - }; - i = 0; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses1[i++], "row addr"); - } - - // add line information check - rz_list_free(line_list); rz_bin_dwarf_debug_abbrev_free(da); rz_bin_free(bin); rz_io_free(io); @@ -832,97 +865,90 @@ bool test_dwarf4_cpp_many_comp_units(void) { // TODO add abbrev checks - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 2, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(li->rows), 61, "rows count"); - - const int test_addresses[] = { - 0x00401160, - 0x00401174, - 0x0040117f, - 0x00401194, - 0x00401198, - 0x004011a1, - 0x004011ac, - 0x004011c1, - 0x004011c5, - 0x004011c9, - 0x004011d0, - 0x004011d4, - 0x004011dd, - 0x004011e3, - 0x004011e7, - 0x004011f0, - 0x004011f6, - 0x004011fc, - 0x00401204, - 0x00401206, - 0x0040120e, - 0x00401219, - 0x00401223, - 0x0040122e, - 0x00401233, - 0x0040123c, - 0x00401240, - 0x0040125c, - 0x0040125f, - 0x00401261, - 0x00401270, - 0x00401280, - 0x00401283, - 0x004012a3, - 0x004012a6, - 0x004012ac, - 0x004012b0, - 0x004012b8, - 0x004012ba, - 0x004012c0, - 0x004012d0, - 0x004012e8, - 0x004012ee, - 0x004012f0, - 0x004012f8, - 0x004012ff, - 0x00401300, - 0x0040131c, - 0x0040131f, - 0x00401321, - 0x00401330, - 0x00401340, - 0x00401348, - 0x0040134e, - 0x00401350, - 0x00401360, - 0x00401378, - 0x0040137e, - 0x00401380, - 0x00401388, - 0x0040138f, - 0x00401390, - 0x00401398, - 0x004013a0, - 0x004013b0, - 0x004013c8, - 0x004013d0, - 0x004013d8, - 0x004013e0, - 0x004013e8, - 0x004013f1, - 0x004013f7, - 0x00401400, - 0x00401408, - 0x0040140f, + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 2, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x401160, 15, 0, "../main.cpp" }, + { 0x401174, 18, 7, "../main.cpp" }, + { 0x40117f, 18, 11, "../main.cpp" }, + { 0x401194, 0, 11, "../main.cpp" }, + { 0x401198, 18, 5, "../main.cpp" }, + { 0x4011a1, 19, 7, "../main.cpp" }, + { 0x4011ac, 19, 11, "../main.cpp" }, + { 0x4011c1, 0, 11, "../main.cpp" }, + { 0x4011c5, 19, 5, "../main.cpp" }, + { 0x4011c9, 20, 7, "../main.cpp" }, + { 0x4011d0, 21, 13, "../main.cpp" }, + { 0x4011d4, 21, 16, "../main.cpp" }, + { 0x4011dd, 21, 10, "../main.cpp" }, + { 0x4011e3, 22, 13, "../main.cpp" }, + { 0x4011e7, 22, 16, "../main.cpp" }, + { 0x4011f0, 22, 10, "../main.cpp" }, + { 0x4011f6, 23, 10, "../main.cpp" }, + { 0x4011fc, 23, 19, "../main.cpp" }, + { 0x401204, 23, 17, "../main.cpp" }, + { 0x401206, 23, 3, "../main.cpp" }, + { 0x40120e, 24, 1, "../main.cpp" }, + { 0x401219, 18, 7, "../main.cpp" }, + { 0x401223, 24, 1, "../main.cpp" }, + { 0x40122e, 19, 7, "../main.cpp" }, + { 0x401233, 18, 7, "../main.cpp" }, + { 0x40123c, 0, 0, NULL }, + { 0x401240, 10, 0, "../main.cpp" }, + { 0x40125c, 10, 10, "../main.cpp" }, + { 0x40125f, 10, 13, "../main.cpp" }, + { 0x401261, 0, 0, NULL }, + { 0x401270, 4, 0, "../main.cpp" }, + { 0x401280, 4, 9, "../main.cpp" }, + { 0x401283, 4, 3, "../main.cpp" }, + { 0x4012a3, 4, 9, "../main.cpp" }, + { 0x4012a6, 4, 12, "../main.cpp" }, + { 0x4012ac, 0, 0, NULL }, + { 0x4012b0, 11, 0, "../main.cpp" }, + { 0x4012b8, 11, 20, "../main.cpp" }, + { 0x4012ba, 0, 0, NULL }, + { 0x4012c0, 11, 0, "../main.cpp" }, + { 0x4012d0, 11, 19, "../main.cpp" }, + { 0x4012e8, 11, 20, "../main.cpp" }, + { 0x4012ee, 0, 0, NULL }, + { 0x4012f0, 12, 0, "../main.cpp" }, + { 0x4012f8, 12, 23, "../main.cpp" }, + { 0x4012ff, 0, 0, NULL }, + { 0x401300, 2, 0, "../mammal.h" }, + { 0x40131c, 2, 12, "../mammal.h" }, + { 0x40131f, 2, 15, "../mammal.h" }, + { 0x401321, 0, 0, NULL }, + { 0x401330, 5, 0, "../main.cpp" }, + { 0x401340, 5, 19, "../main.cpp" }, + { 0x401348, 5, 19, "../main.cpp" }, + { 0x40134e, 0, 0, NULL }, + { 0x401350, 5, 0, "../main.cpp" }, + { 0x401360, 5, 18, "../main.cpp" }, + { 0x401378, 5, 19, "../main.cpp" }, + { 0x40137e, 0, 0, NULL }, + { 0x401380, 6, 0, "../main.cpp" }, + { 0x401388, 6, 24, "../main.cpp" }, + { 0x40138f, 0, 0, NULL }, + { 0x401390, 3, 0, "../mammal.cpp" }, + { 0x401398, 3, 22, "../mammal.cpp" }, + { 0x4013a0, 3, 0, "../mammal.cpp" }, + { 0x4013b0, 3, 21, "../mammal.cpp" }, + { 0x4013c8, 3, 22, "../mammal.cpp" }, + { 0x4013d0, 4, 0, "../mammal.cpp" }, + { 0x4013d8, 4, 24, "../mammal.cpp" }, + { 0x4013e0, 10, 0, "../mammal.cpp" }, + { 0x4013e8, 12, 14, "../mammal.cpp" }, + { 0x4013f1, 12, 2, "../mammal.cpp" }, + { 0x4013f7, 0, 0, NULL }, + { 0x401400, 7, 0, "../mammal.cpp" }, + { 0x401408, 7, 19, "../mammal.cpp" }, + { 0x40140f, 0, 0, NULL } }; + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - RzBinSourceRow *row; - RzListIter *iter; - int i = 0; - rz_list_foreach (li->rows, iter, row) { - mu_assert_eq(row->address, test_addresses[i++], "Line number statement address doesn't match"); - } - - rz_list_free(line_list); rz_bin_free(bin); rz_io_free(io); mu_end; @@ -944,45 +970,26 @@ bool test_dwarf4_multidir_comp_units(void) { RzBinDwarfDebugInfo *info = rz_bin_dwarf_parse_info(bin->cur, da); mu_assert_notnull(info, "info"); - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, info, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 2, "line info count"); - - const RzBinSourceRow test_rows0[] = { - { 0x1139, "/home/florian/dev/dwarf-comp-units/main.c", 6, 12 }, - { 0x113d, "/home/florian/dev/dwarf-comp-units/main.c", 7, 2 }, - { 0x115f, "/home/florian/dev/dwarf-comp-units/main.c", 8, 2 }, - { 0x1181, "/home/florian/dev/dwarf-comp-units/main.c", 9, 9 }, - { 0x1186, "/home/florian/dev/dwarf-comp-units/main.c", 10, 1 }, - { 0x1188, "/home/florian/dev/dwarf-comp-units/main.c", 0, 0 } + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, info, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 2, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x1139, 6, 12, "/home/florian/dev/dwarf-comp-units/main.c" }, + { 0x113d, 7, 2, "/home/florian/dev/dwarf-comp-units/main.c" }, + { 0x115f, 8, 2, "/home/florian/dev/dwarf-comp-units/main.c" }, + { 0x1181, 9, 9, "/home/florian/dev/dwarf-comp-units/main.c" }, + { 0x1186, 10, 1, "/home/florian/dev/dwarf-comp-units/main.c" }, + { 0x1188, 2, 31, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c" }, + { 0x1192, 3, 11, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c" }, + { 0x1198, 3, 20, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c" }, + { 0x11a1, 3, 16, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c" }, + { 0x11a3, 4, 1, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c" }, + { 0x11a5, 0, 0, NULL } }; + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - const RzBinSourceRow test_rows1[] = { - { 0x1188, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 2, 31 }, - { 0x1192, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 3, 11 }, - { 0x1198, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 3, 20 }, - { 0x11a1, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 3, 16 }, - { 0x11a3, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 4, 1 }, - { 0x11a5, "/home/florian/dev/dwarf-comp-units/some_subfolder/subfile.c", 0, 0 } - }; - - const RzBinSourceRow *test_rows[] = { test_rows0, test_rows1 }; - - for (size_t i = 0; i < 2; i++) { - RzBinDwarfLineInfo *li = rz_list_get_n(line_list, i); - mu_assert_eq(rz_list_length(li->rows), i ? RZ_ARRAY_SIZE(test_rows1) : RZ_ARRAY_SIZE(test_rows0), "rows count"); - RzBinSourceRow *row; - RzListIter *iter; - size_t j = 0; - rz_list_foreach (li->rows, iter, row) { - const RzBinSourceRow *expect = &test_rows[i][j++]; - mu_assert_eq(row->address, expect->address, "Row addr"); - mu_assert_streq(row->file, expect->file, "Row file"); - mu_assert_eq(row->line, expect->line, "Row line"); - mu_assert_eq(row->column, expect->column, "Row column"); - } - } - - rz_list_free(line_list); rz_bin_dwarf_debug_info_free(info); rz_bin_dwarf_debug_abbrev_free(da); rz_bin_free(bin); @@ -999,45 +1006,490 @@ bool test_big_endian_dwarf2(void) { bool res = rz_bin_open(bin, "bins/elf/ppc64_sudoku_dwarf", &opt); mu_assert("couldn't open file", res); - RzList *line_list = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_ROWS); - mu_assert_eq(rz_list_length(line_list), 1, "Amount of line information parse doesn't match"); - RzBinDwarfLineInfo *li = rz_list_first(line_list); - mu_assert_eq(rz_list_length(li->rows), 475, "rows count"); - - const RzBinSourceRow test_rows[] = { - { 0x10000ec4, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 30, 1 }, - { 0x10000f18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 31, 5 }, - { 0x10000f18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 31, 11 }, - { 0x10000f28, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 32, 5 }, - { 0x10000f28, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 32, 22 }, - { 0x10000f2c, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 31, 11 }, - { 0x10000f30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 32, 13 }, - { 0x10000f34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 34, 17 }, - { 0x10000f38, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 53, 22 }, - { 0x10000f44, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 38, 54 }, - { 0x10000f44, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h", 335, 2 }, - { 0x10000f44, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream", 570, 18 }, - { 0x10000f5c, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream", 572, 14 }, - { 0x10000f60, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp", 42, 22 }, - { 0x10000f60, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h", 335, 2 }, - { 0x10000f60, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream", 570, 18 } + RzBinDwarfLineInfo *li = rz_bin_dwarf_parse_line(bin->cur, NULL, RZ_BIN_DWARF_LINE_INFO_MASK_OPS | RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + mu_assert_notnull(li, "line info"); + mu_assert_eq(rz_list_length(li->units), 1, "line units count"); + mu_assert_notnull(li->lines, "line info"); + const RzBinSourceLineSample test_line_samples[] = { + { 0x10000ec4, 30, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f18, 31, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f18, 31, 11, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f28, 32, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f28, 32, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f2c, 31, 11, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f30, 32, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f34, 34, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f38, 53, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f44, 38, 54, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f44, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10000f44, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10000f5c, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10000f60, 42, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f60, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10000f60, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10000f78, 53, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f78, 53, 18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f80, 53, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f90, 53, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000f98, 54, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fa0, 34, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fa0, 55, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fa4, 36, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fb4, 38, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fc0, 38, 35, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fcc, 39, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fcc, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10000fcc, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10000fe4, 40, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10000fe4, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10000fe4, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10000ffc, 41, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001008, 41, 35, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001014, 41, 54, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001014, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10001014, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x1000102c, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001030, 46, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000103c, 46, 35, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001048, 47, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001048, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x10001048, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001060, 48, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001060, 48, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001074, 49, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001080, 49, 35, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000108c, 50, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000108c, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x1000108c, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010a4, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010a8, 46, 54, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100010a8, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x100010a8, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010c0, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010c4, 49, 54, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100010c4, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x100010c4, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010dc, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010e0, 53, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100010e0, 335, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/char_traits.h" }, + { 0x100010e0, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010f8, 572, 14, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100010fc, 54, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100010fc, 600, 19, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001108, 450, 30, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x10001114, 49, 7, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x1000111c, 874, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001128, 875, 4, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001128, 875, 51, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x1000112c, 600, 19, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x1000113c, 622, 25, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001144, 55, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001144, 55, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001154, 55, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000115c, 32, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000115c, 34, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001164, 32, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001178, 32, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001178, 34, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000117c, 34, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001180, 570, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100011ac, 50, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x100011b4, 876, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011b4, 876, 21, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011c0, 877, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011c0, 877, 27, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011c4, 877, 23, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011e0, 877, 27, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x100011e4, 55, 42, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100011e4, 600, 19, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x100011f0, 450, 30, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x100011fc, 49, 7, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x10001204, 874, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001210, 875, 4, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001210, 875, 51, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001214, 600, 19, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001224, 622, 25, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x1000122c, 600, 46, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/ostream" }, + { 0x10001230, 50, 18, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/basic_ios.h" }, + { 0x10001238, 876, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001238, 876, 21, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001244, 877, 2, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001244, 877, 27, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001248, 877, 23, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001264, 877, 27, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/bits/locale_facets.h" }, + { 0x10001268, 58, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012bc, 61, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012bc, 62, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012bc, 62, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012c4, 66, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012c8, 64, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012d4, 66, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012d4, 66, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012d8, 64, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012d8, 64, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012e0, 62, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012e0, 62, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012ec, 69, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012ec, 69, 15, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012f4, 70, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012f4, 70, 15, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100012f8, 71, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001308, 74, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001314, 75, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001334, 84, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001334, 85, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001334, 85, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001338, 85, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001348, 87, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001350, 88, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001350, 88, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000136c, 75, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001374, 98, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001374, 99, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001374, 99, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001378, 99, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001388, 101, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001390, 102, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001390, 102, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013a8, 105, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013a8, 106, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013a8, 106, 18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013ac, 106, 18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013ac, 107, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013b4, 110, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013bc, 77, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013bc, 78, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013bc, 78, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013c0, 78, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013d0, 80, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013d8, 81, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013d8, 81, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013e8, 91, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013e8, 92, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013e8, 92, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013ec, 92, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100013fc, 94, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001404, 95, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001404, 95, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001420, 134, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001420, 135, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001420, 136, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001420, 137, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001420, 137, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001430, 136, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001440, 137, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001440, 137, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001444, 139, 6, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001450, 140, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000145c, 142, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000145c, 142, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000145c, 144, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001460, 145, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001474, 150, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001474, 151, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001474, 152, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001474, 153, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001474, 153, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001480, 152, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001490, 153, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001490, 153, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001498, 155, 2, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014a4, 155, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014b0, 157, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014b0, 157, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014b0, 159, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014b4, 160, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014c8, 165, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014cc, 166, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014cc, 167, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014cc, 168, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014cc, 168, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014d0, 168, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014d8, 170, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014d8, 170, 27, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014dc, 170, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014ec, 167, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100014f4, 176, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001500, 176, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000150c, 172, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000150c, 172, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000150c, 174, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000150c, 174, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001514, 174, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001514, 176, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001528, 174, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001528, 174, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001528, 176, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001534, 174, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001534, 174, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001534, 176, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001540, 176, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000154c, 180, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000154c, 180, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001550, 180, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001560, 167, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001568, 186, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001574, 186, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001580, 182, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001580, 182, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001580, 184, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001580, 184, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001588, 184, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001588, 186, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000159c, 184, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000159c, 184, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000159c, 186, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015a8, 184, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015a8, 184, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015a8, 186, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015b4, 186, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015c0, 190, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015c0, 190, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015c4, 268, 12, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015c8, 190, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015dc, 196, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015e8, 196, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015f4, 192, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015f4, 192, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015f4, 194, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015f4, 194, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015fc, 194, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100015fc, 196, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001610, 194, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001610, 194, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001610, 196, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000161c, 194, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000161c, 194, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000161c, 196, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001628, 196, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001634, 201, 10, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001634, 201, 28, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001638, 201, 10, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001640, 203, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001640, 203, 27, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001644, 203, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001654, 167, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000165c, 209, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001668, 209, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001674, 205, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001674, 205, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001674, 207, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001674, 207, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000167c, 207, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000167c, 209, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001690, 207, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001690, 207, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001690, 209, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000169c, 207, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000169c, 207, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000169c, 209, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016a8, 209, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016b4, 213, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016b4, 213, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016b8, 213, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016c8, 167, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016d0, 219, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016dc, 219, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016e8, 215, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016e8, 215, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016e8, 217, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016e8, 217, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016f0, 217, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100016f0, 219, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001704, 217, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001704, 217, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001704, 219, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001710, 217, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001710, 217, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001710, 219, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000171c, 219, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001728, 223, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001728, 223, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000172c, 268, 12, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001730, 223, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001744, 229, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001750, 229, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000175c, 225, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000175c, 225, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000175c, 227, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000175c, 227, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001764, 227, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001764, 229, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001778, 227, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001778, 227, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001778, 229, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001784, 227, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001784, 227, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001784, 229, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001790, 229, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000179c, 234, 10, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000179c, 234, 28, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017a0, 268, 12, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017a4, 234, 10, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017ac, 236, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017ac, 236, 27, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017b0, 236, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017c4, 242, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017d0, 242, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017dc, 238, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017dc, 238, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017dc, 240, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017dc, 240, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017e4, 240, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017e4, 242, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017f8, 240, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017f8, 240, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100017f8, 242, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001804, 240, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001804, 240, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001804, 242, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001810, 242, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000181c, 246, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000181c, 246, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001820, 246, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001830, 167, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001838, 252, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001844, 252, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001850, 248, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001850, 248, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001850, 250, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001850, 250, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001858, 250, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001858, 252, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000186c, 250, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000186c, 250, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000186c, 252, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001878, 250, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001878, 250, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001878, 252, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001884, 252, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001890, 256, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001890, 256, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001894, 268, 12, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001898, 256, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018ac, 262, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018b8, 262, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018c4, 258, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018c4, 258, 30, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018c4, 260, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018c4, 260, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018cc, 260, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018cc, 262, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018e0, 260, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018e0, 260, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018e0, 262, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018ec, 260, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018ec, 260, 34, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018ec, 262, 21, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100018f8, 262, 41, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001904, 267, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000190c, 269, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000190c, 270, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000191c, 113, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000194c, 115, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001954, 115, 15, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001954, 115, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000195c, 116, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000195c, 116, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001960, 116, 37, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001964, 116, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001974, 117, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001974, 117, 32, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001978, 119, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001978, 119, 18, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001984, 119, 40, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x1000198c, 119, 36, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001998, 119, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019a0, 119, 54, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019ac, 119, 40, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019b4, 121, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019b4, 121, 36, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019c4, 122, 6, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019c4, 122, 11, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019cc, 128, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019cc, 129, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019f4, 126, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x100019f4, 126, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/grid.cpp" }, + { 0x10001a0c, 10, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a0c, 11, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a0c, 11, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a10, 11, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a1c, 13, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a30, 16, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a30, 17, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a30, 17, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a34, 17, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a40, 19, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a54, 11, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a54, 11, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a54, 22, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a54, 23, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a58, 23, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a64, 25, 8, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a64, 25, 10, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a6c, 26, 8, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a6c, 29, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a7c, 17, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a7c, 17, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a7c, 31, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a7c, 32, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a80, 32, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a8c, 34, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a8c, 34, 11, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a94, 35, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001a94, 38, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001aa4, 41, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001aa4, 42, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001aa4, 42, 16, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001aa8, 42, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001ab4, 44, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001ac8, 16, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ae4, 17, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ae4, 18, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ae4, 20, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ae4, 20, 16, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001aec, 22, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001aec, 22, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001af8, 30, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001af8, 30, 26, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b04, 31, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b04, 31, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b10, 32, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b10, 32, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b28, 40, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b28, 40, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b3c, 42, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b44, 24, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b44, 26, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b44, 26, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b50, 26, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b54, 27, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b54, 27, 15, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b68, 17, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001b68, 17, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001b68, 28, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b6c, 28, 9, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b78, 34, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b78, 42, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001b78, 42, 16, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/alphanum.cpp" }, + { 0x10001b7c, 34, 14, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b88, 36, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b88, 36, 23, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b94, 37, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001b94, 37, 24, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ba0, 38, 13, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001ba0, 38, 22, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001bb4, 42, 17, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001bb8, 44, 5, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001bb8, 45, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001be0, 45, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001bf8, 74, 25, "/home/hound/Crosscompilation/powerpc64-linux-musl-cross/powerpc64-linux-musl/include/c++/9.3.0/iostream" }, + { 0x10001c28, 45, 1, "/home/hound/Projects/r2test/dwarf/cpp/sudoku_cpp/play.cpp" }, + { 0x10001c48, 0, 0, NULL } }; + assert_line_samples_eq(li->lines, RZ_ARRAY_SIZE(test_line_samples), test_line_samples); + rz_bin_dwarf_line_info_free(li); - RzBinSourceRow *row; - RzListIter *iter; - int i = 0; - rz_list_foreach (li->rows, iter, row) { - const RzBinSourceRow *expect = &test_rows[i++]; - mu_assert_eq(row->address, expect->address, "Row addr"); - mu_assert_streq(row->file, expect->file, "Row file"); - mu_assert_eq(row->line, expect->line, "Row line"); - mu_assert_eq(row->column, expect->column, "Row column"); - if (i == 0x10) { - break; - } - } - - rz_list_free(line_list); rz_bin_free(bin); rz_io_free(io); mu_end; @@ -1099,6 +1551,7 @@ bool test_dwarf3_aranges(void) { } bool all_tests() { + srand(time(0)); mu_run_test(test_dwarf3_c_basic); mu_run_test(test_dwarf_cpp_empty_line_info); mu_run_test(test_dwarf2_cpp_many_comp_units); From 59b196da623bb11b7f188edd356784e58ac5dfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 24 Mar 2021 21:33:29 +0100 Subject: [PATCH 3/5] Refactor Rest to use RzBinSourceLineInfo --- librz/bin/bfile.c | 7 - librz/bin/bobj.c | 5 +- librz/bin/dbginfo.c | 144 ++++------- librz/bin/format/dex/dex.h | 2 +- librz/bin/format/mach0/coresymbolication.c | 23 -- librz/bin/meson.build | 3 - librz/bin/p/bin_cgc.c | 1 - librz/bin/p/bin_dbginfo_dex.c | 29 --- librz/bin/p/bin_dbginfo_elf.c | 36 --- librz/bin/p/bin_dbginfo_elf64.c | 6 - librz/bin/p/bin_dex.c | 74 ++---- librz/bin/p/bin_elf.c | 1 - librz/bin/p/bin_elf64.c | 1 - librz/bin/p/bin_symbols.c | 30 +++ librz/core/cbin.c | 279 +++++++++------------ librz/core/cmd_meta.c | 196 +-------------- librz/include/rz_bin.h | 40 +-- librz/include/rz_core.h | 3 + test/db/abi/compilers/clang | 2 +- test/db/abi/compilers/clang_64 | 2 +- test/db/abi/compilers/gcc | 2 +- test/db/abi/compilers/gcc_64 | 2 +- test/db/cmd/cmd_meta | 75 ------ test/db/cmd/dwarf | 16 +- test/db/formats/dex | 37 ++- test/db/formats/mach0/coresymbolication | 92 ++++++- test/db/formats/mangling/bin | 2 +- test/db/tools/rz_bin | 2 +- 28 files changed, 367 insertions(+), 745 deletions(-) delete mode 100644 librz/bin/p/bin_dbginfo_dex.c delete mode 100644 librz/bin/p/bin_dbginfo_elf.c delete mode 100644 librz/bin/p/bin_dbginfo_elf64.c diff --git a/librz/bin/bfile.c b/librz/bin/bfile.c index ae92102951d..a48fc99ff3e 100644 --- a/librz/bin/bfile.c +++ b/librz/bin/bfile.c @@ -445,8 +445,6 @@ RZ_IPI RzBinFile *rz_bin_file_new(RzBin *bin, const char *file, ut64 file_sz, in bf->xtr_data = rz_list_newf((RzListFree)rz_bin_xtrdata_free); bf->xtr_obj = NULL; bf->sdb = sdb_new0(); - bf->sdb_addrinfo = sdb_new0(); //ns (bf->sdb, "addrinfo", 1); - // bf->sdb_addrinfo->refs++; } return bf; } @@ -699,11 +697,6 @@ RZ_API void rz_bin_file_free(void /*RzBinFile*/ *_bf) { if (bf->curxtr && bf->curxtr->destroy && bf->xtr_obj) { bf->curxtr->free_xtr((void *)(bf->xtr_obj)); } - // TODO: unset related sdb namespaces - if (bf->sdb_addrinfo) { - sdb_free(bf->sdb_addrinfo); - bf->sdb_addrinfo = NULL; - } free(bf->file); rz_bin_object_free(bf->o); rz_list_free(bf->xtr_data); diff --git a/librz/bin/bobj.c b/librz/bin/bobj.c index 61c9166fecb..841b98cb4aa 100644 --- a/librz/bin/bobj.c +++ b/librz/bin/bobj.c @@ -49,7 +49,7 @@ static void object_delete_items(RzBinObject *o) { rz_list_free(o->classes); ht_pp_free(o->classes_ht); ht_pp_free(o->methods_ht); - rz_list_free(o->lines); + rz_bin_source_line_info_free(o->lines); sdb_free(o->kv); rz_list_free(o->mem); for (i = 0; i < RZ_BIN_SYM_LAST; i++) { @@ -179,7 +179,6 @@ RZ_IPI RzBinObject *rz_bin_object_new(RzBinFile *bf, RzBinPlugin *plugin, ut64 b if (sdb) { Sdb *bdb = bf->sdb; // sdb_new0 (); sdb_ns_set(bdb, "info", o->kv); - sdb_ns_set(bdb, "addrinfo", bf->sdb_addrinfo); o->kv = bdb; // bf->sdb = o->kv; // bf->sdb_info = o->kv; @@ -192,8 +191,6 @@ RZ_IPI RzBinObject *rz_bin_object_new(RzBinFile *bf, RzBinPlugin *plugin, ut64 b /* And if any namespace is referenced backwards it gets * double-freed */ // bf->sdb_info = sdb_ns (bf->sdb, "info", 1); - // bf->sdb_addrinfo = sdb_ns (bf->sdb, "addrinfo", 1); - // bf->sdb_addrinfo->refs++; sdb_ns_set(sdb, "cur", bdb); // bf->sdb); const char *fdns = sdb_fmt("fd.%d", bf->fd); sdb_ns_set(sdb, fdns, bdb); // bf->sdb); diff --git a/librz/bin/dbginfo.c b/librz/bin/dbginfo.c index 7860ca719e6..f1be28082d0 100644 --- a/librz/bin/dbginfo.c +++ b/librz/bin/dbginfo.c @@ -6,14 +6,6 @@ #include #include -RZ_API void rz_bin_source_row_free(RzBinSourceRow *row) { - if (!row) { - return; - } - free(row->file); - free(row); -} - RZ_API void rz_bin_source_line_info_builder_init(RzBinSourceLineInfoBuilder *builder) { rz_vector_init(&builder->samples, sizeof(RzBinSourceLineSample), NULL, NULL); rz_str_constpool_init(&builder->filename_pool); @@ -207,16 +199,22 @@ RZ_API const RzBinSourceLineSample *rz_bin_source_line_info_get_next(const RzBin RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *line) { rz_return_val_if_fail(bin, false); - RzBinFile *binfile = rz_bin_cur(bin); - RzBinObject *o = rz_bin_cur_object(bin); - RzBinPlugin *cp = rz_bin_file_cur_plugin(binfile); - ut64 baddr = rz_bin_get_baddr(bin); - if (cp && cp->dbginfo) { - if (o && addr >= baddr && addr < baddr + bin->cur->o->size) { - if (cp->dbginfo->get_line) { - return cp->dbginfo->get_line( - bin->cur, addr, file, len, line); - } + if (!bin->cur || !bin->cur->o || !bin->cur->o->lines) { + return NULL; + } + const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(bin->cur->o->lines, addr); + if (!s || s->address != addr) { + // consider only exact matches, not inside of samples + return false; + } + if (line) { + *line = s->line; + } + if (file && len) { + if (s->file) { + rz_str_ncpy(file, s->file, len); + } else { + *file = 0; } } return false; @@ -224,99 +222,45 @@ RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *li RZ_API char *rz_bin_addr2text(RzBin *bin, ut64 addr, int origin) { rz_return_val_if_fail(bin, NULL); - char file[4096]; - int line; - char *out = NULL, *out2 = NULL; - char *file_nopath = NULL; - if (!bin->cur) { + if (!bin->cur || !bin->cur->o || !bin->cur->o->lines) { + return NULL; + } + const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(bin->cur->o->lines, addr); + if (s && s->address != addr) { + // consider only exact matches, not inside of samples return NULL; } - char *key = rz_str_newf("0x%" PFMT64x, addr); - char *file_line = sdb_get(bin->cur->sdb_addrinfo, key, 0); - if (file_line) { - char *token = strchr(file_line, '|'); - if (token) { - *token++ = 0; - line = atoi(token); - out = rz_file_slurp_line(file_line, line, 0); - *token++ = ':'; + while (s && !s->file) { + s = rz_bin_source_line_info_get_next(bin->cur->o->lines, s); + } + if (!s) { + return NULL; + } + const char *file_nopath; + if (origin > 1) { + file_nopath = s->file; + } else { + file_nopath = strrchr(s->file, '/'); + if (file_nopath) { + file_nopath++; } else { - return file_line; + file_nopath = s->file; } } - free(key); + if (!s->line) { + return strdup(file_nopath); + } + char *out = rz_file_slurp_line(s->file, s->line, 0); if (out) { - if (origin > 1) { - file_nopath = file_line; - } else { - file_nopath = strrchr(file_line, '/'); - if (file_nopath) { - file_nopath++; - } else { - file_nopath = file_line; - } - } + rz_str_trim(out); if (origin) { - char *res = rz_str_newf("%s:%d%s%s", - file_nopath ? file_nopath : "", - line, file_nopath ? " " : "", + char *res = rz_str_newf("%s:%d %s", + file_nopath, s->line, out ? out : ""); free(out); out = res; } - free(file_line); return out; } - RZ_FREE(file_line); - - file[0] = 0; - if (rz_bin_addr2line(bin, addr, file, sizeof(file), &line)) { - if (bin->srcdir && *bin->srcdir) { - char *slash = strrchr(file, '/'); - char *nf = rz_str_newf("%s/%s", bin->srcdir, slash ? slash + 1 : file); - strncpy(file, nf, sizeof(file) - 1); - free(nf); - } - // TODO: this is slow. must use a cached pool of mapped files and line:off entries - out = rz_file_slurp_line(file, line, 0); - if (!out) { - if (origin > 1) { - file_nopath = file; - } else { - file_nopath = strrchr(file, '/'); - if (file_nopath) { - file_nopath++; - } else { - file_nopath = file; - } - } - return rz_str_newf("%s:%d", file_nopath ? file_nopath : "", line); - } - out2 = malloc((strlen(file) + 64 + strlen(out)) * sizeof(char)); - if (origin > 1) { - file_nopath = NULL; - } else { - file_nopath = strrchr(file, '/'); - } - if (origin) { - snprintf(out2, strlen(file) + 63 + strlen(out), "%s:%d%s%s", - file_nopath ? file_nopath + 1 : file, line, *out ? " " : "", out); - } else { - snprintf(out2, 64, "%s", out); - } - free(out); - } - return out2; -} - -RZ_API char *rz_bin_addr2fileline(RzBin *bin, ut64 addr) { - rz_return_val_if_fail(bin, NULL); - char file[1024]; - int line = 0; - - if (rz_bin_addr2line(bin, addr, file, sizeof(file) - 1, &line)) { - char *file_nopath = strrchr(file, '/'); - return rz_str_newf("%s:%d", file_nopath ? file_nopath + 1 : file, line); - } - return NULL; + return rz_str_newf("%s:%" PFMT32u, file_nopath, s->line); } diff --git a/librz/bin/format/dex/dex.h b/librz/bin/format/dex/dex.h index e74fd980edf..a87169ad085 100644 --- a/librz/bin/format/dex/dex.h +++ b/librz/bin/format/dex/dex.h @@ -123,7 +123,7 @@ typedef struct rz_bin_dex_obj_t { RzList *trycatch_list; RzList *imports_list; RzList *classes_list; - RzList *lines_list; + RzBinSourceLineInfo *lines; //< moved out when bin queries it to avoid dup ut64 code_from; ut64 code_to; char *version; diff --git a/librz/bin/format/mach0/coresymbolication.c b/librz/bin/format/mach0/coresymbolication.c index 02461de8c53..d091bfa10ab 100644 --- a/librz/bin/format/mach0/coresymbolication.c +++ b/librz/bin/format/mach0/coresymbolication.c @@ -116,27 +116,6 @@ ut64 rz_coresym_cache_element_pa2va(RzCoreSymCacheElement *element, ut64 pa) { return pa; } -static void meta_add_fileline(RzBinFile *bf, ut64 vaddr, ut32 size, RzCoreSymCacheElementFLC *flc) { - Sdb *s = bf->sdb_addrinfo; - if (!s) { - return; - } - char aoffset[64]; - ut64 cursor = vaddr; - ut64 end = cursor + RZ_MAX(size, 1); - char *fileline = rz_str_newf("%s:%d", flc->file, flc->line); - while (cursor < end) { - char *aoffsetptr = sdb_itoa(cursor, aoffset, 16); - if (!aoffsetptr) { - break; - } - sdb_set(s, aoffsetptr, fileline, 0); - sdb_set(s, fileline, aoffsetptr, 0); - cursor += 2; - } - free(fileline); -} - static char *str_dup_safe(const ut8 *b, const ut8 *str, const ut8 *end) { if (str >= b && str < end) { int len = rz_str_nlen((const char *)str, end - str); @@ -351,7 +330,6 @@ RzCoreSymCacheElement *rz_coresym_cache_element_new(RzBinFile *bf, RzBuffer *buf continue; } cursor += RZ_CS_EL_SIZE_LSYM; - meta_add_fileline(bf, rz_coresym_cache_element_pa2va(result, lsym->sym.paddr), lsym->sym.size, &lsym->flc); } } if (hdr->n_line_info) { @@ -374,7 +352,6 @@ RzCoreSymCacheElement *rz_coresym_cache_element_new(RzBinFile *bf, RzBuffer *buf break; } cursor += RZ_CS_EL_SIZE_LINFO; - meta_add_fileline(bf, rz_coresym_cache_element_pa2va(result, info->paddr), info->size, &info->flc); } } diff --git a/librz/bin/meson.build b/librz/bin/meson.build index c886dcd3d59..f41c5c6e326 100644 --- a/librz/bin/meson.build +++ b/librz/bin/meson.build @@ -17,9 +17,6 @@ rz_bin_sources = [ 'p/bin_bootimg.c', 'p/bin_cgc.c', 'p/bin_coff.c', - 'p/bin_dbginfo_dex.c', - 'p/bin_dbginfo_elf.c', - 'p/bin_dbginfo_elf64.c', 'p/bin_dex.c', 'p/bin_dmp64.c', 'p/bin_dol.c', diff --git a/librz/bin/p/bin_cgc.c b/librz/bin/p/bin_cgc.c index 75ccf448cb3..810a57291ae 100644 --- a/librz/bin/p/bin_cgc.c +++ b/librz/bin/p/bin_cgc.c @@ -122,7 +122,6 @@ RzBinPlugin rz_bin_plugin_cgc = { .size = &size, .libs = &libs, .relocs = &relocs, - .dbginfo = &rz_bin_dbginfo_elf, .create = &create, .patch_relocs = &patch_relocs, .write = &rz_bin_write_elf, diff --git a/librz/bin/p/bin_dbginfo_dex.c b/librz/bin/p/bin_dbginfo_dex.c deleted file mode 100644 index 9ee92a48841..00000000000 --- a/librz/bin/p/bin_dbginfo_dex.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-FileCopyrightText: 2009-2020 nibble -// SPDX-FileCopyrightText: 2009-2020 montekki -// SPDX-FileCopyrightText: 2009-2020 pancake -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#include - -static bool get_line(RzBinFile *bf, ut64 addr, char *file, int len, int *line) { - if (bf->sdb_addrinfo) { - char offset[64]; - char *offset_ptr = sdb_itoa(addr, offset, 16); - char *ret = sdb_get(bf->sdb_addrinfo, offset_ptr, 0); - if (ret) { - char *p = strchr(ret, '|'); - if (p) { - *p = '\0'; - strncpy(file, ret, len); - *line = atoi(p + 1); - return true; - } - } - } - return false; -} - -RzBinDbgInfo rz_bin_dbginfo_dex = { - .get_line = &get_line, -}; diff --git a/librz/bin/p/bin_dbginfo_elf.c b/librz/bin/p/bin_dbginfo_elf.c deleted file mode 100644 index 03d9a08de72..00000000000 --- a/librz/bin/p/bin_dbginfo_elf.c +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-FileCopyrightText: 2009-2020 nibble -// SPDX-FileCopyrightText: 2009-2020 montekki -// SPDX-FileCopyrightText: 2009-2020 pancake -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#include - -// TODO: use proper dwarf api here.. or deprecate -static bool get_line(RzBinFile *bf, ut64 addr, char *file, int len, int *line) { - if (bf->sdb_addrinfo) { - char offset[64]; - char *offset_ptr = sdb_itoa(addr, offset, 16); - char *ret = sdb_get(bf->sdb_addrinfo, offset_ptr, 0); - if (ret) { - char *p = strchr(ret, '|'); - if (p) { - *p = '\0'; - strncpy(file, ret, len); - *line = atoi(p + 1); - return true; - } - } - } - return false; -} - -#if RZ_BIN_ELF64 -RzBinDbgInfo rz_bin_dbginfo_elf64 = { - .get_line = &get_line, -}; -#else -RzBinDbgInfo rz_bin_dbginfo_elf = { - .get_line = &get_line, -}; -#endif diff --git a/librz/bin/p/bin_dbginfo_elf64.c b/librz/bin/p/bin_dbginfo_elf64.c deleted file mode 100644 index 7514a8da5ab..00000000000 --- a/librz/bin/p/bin_dbginfo_elf64.c +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: 2009-2020 nibble -// SPDX-FileCopyrightText: 2009-2020 pancake -// SPDX-License-Identifier: LGPL-3.0-only - -#define RZ_BIN_ELF64 1 -#include "bin_dbginfo_elf.c" diff --git a/librz/bin/p/bin_dex.c b/librz/bin/p/bin_dex.c index ae530ceb98e..3c46211bd3c 100644 --- a/librz/bin/p/bin_dex.c +++ b/librz/bin/p/bin_dex.c @@ -380,7 +380,7 @@ static RzList *dex_method_signature2(RzBinDexObj *bin, int method_idx) { // XXX. this is using binfile->buf directly :( // https://github.com/android/platform_dalvik/blob/0641c2b4836fae3ee8daf6c0af45c316c84d5aeb/libdex/DexDebugInfo.cpp#L312 // https://github.com/android/platform_dalvik/blob/0641c2b4836fae3ee8daf6c0af45c316c84d5aeb/libdex/DexDebugInfo.cpp#L141 -static void dex_parse_debug_item(RzBinFile *bf, RzBinDexClass *c, int MI, int MA, int paddr, int ins_size, int insns_size, char *class_name, int regsz, int debug_info_off) { +static void dex_parse_debug_item(RzBinFile *bf, RzBinDexClass *c, int MI, int MA, int paddr, int ins_size, int insns_size, char *class_name, int regsz, int debug_info_off, RzBinSourceLineInfoBuilder *bob) { RzBin *rbin = bf->rbin; RzBinDexObj *dex = bf->o->bin_obj; // bin .. unnecessary arg // runtime error: pointer index expression with base 0x000000004402 overflowed to 0xffffffffff0043fc @@ -623,38 +623,15 @@ static void dex_parse_debug_item(RzBinFile *bf, RzBinDexClass *c, int MI, int MA } } - if (!bf->sdb_addrinfo) { - bf->sdb_addrinfo = sdb_new0(); - } - RzListIter *iter1; struct dex_debug_position_t *pos; - // Loading the debug info takes too much time and nobody uses this afaik - // 0.5s of 5s is spent in this loop - rz_list_foreach (debug_positions, iter1, pos) { - const char *line = getstr(dex, pos->source_file_idx); - char offset[64] = { 0 }; - if (!line || !*line) { - continue; - } - char *fileline = rz_str_newf("%s|%" PFMT64d, line, pos->line); - char *offset_ptr = sdb_itoa(pos->address + paddr, offset, 16); - sdb_set(bf->sdb_addrinfo, offset_ptr, fileline, 0); - sdb_set(bf->sdb_addrinfo, fileline, offset_ptr, 0); - free(fileline); - - RzBinSourceRow *row = RZ_NEW0(RzBinSourceRow); - if (!row) { - dexdump = false; - break; - } - if (line) { - row->file = strdup(line); - row->address = pos->address; - row->line = pos->line; - rz_list_append(dex->lines_list, row); - } else { - free(row); + if (bob) { + rz_list_foreach (debug_positions, iter1, pos) { + const char *file = getstr(dex, pos->source_file_idx); + if (!file || !*file) { + continue; + } + rz_bin_source_line_info_builder_push_sample(bob, pos->address + paddr, pos->line, 0, file); } } if (!dexdump) { @@ -1129,7 +1106,7 @@ static void parse_dex_class_fields(RzBinFile *bf, RzBinDexClass *c, RzBinClass * // TODO: refactor this method // XXX it needs a lot of love!!! static void parse_dex_class_method(RzBinFile *bf, RzBinDexClass *c, RzBinClass *cls, - int *sym_count, ut64 DM, int *methods, bool is_direct) { + int *sym_count, ut64 DM, int *methods, bool is_direct, RzBinSourceLineInfoBuilder *bob) { PrintfCallback cb_printf = bf->rbin->cb_printf; RzBinDexObj *dex = bf->o->bin_obj; bool bin_dbginfo = bf->rbin->want_dbginfo; @@ -1437,7 +1414,7 @@ static void parse_dex_class_method(RzBinFile *bf, RzBinDexClass *c, RzBinClass * if (bin_dbginfo) { ut64 addr = rz_buf_tell(bf->buf); dex_parse_debug_item(bf, c, MI, MA, sym->paddr, ins_size, - insns_size, cls->name, regsz, debug_info_off); + insns_size, cls->name, regsz, debug_info_off, bob); rz_buf_seek(bf->buf, addr, RZ_BUF_SET); } } else if (MC > 0) { @@ -1453,7 +1430,7 @@ static void parse_dex_class_method(RzBinFile *bf, RzBinDexClass *c, RzBinClass * } } -static void parse_class(RzBinFile *bf, RzBinDexClass *c, int class_index, int *methods, int *sym_count) { +static void parse_class(RzBinFile *bf, RzBinDexClass *c, int class_index, int *methods, int *sym_count, RzBinSourceLineInfoBuilder *bob) { rz_return_if_fail(bf && bf->o && c); RzBinDexObj *dex = bf->o->bin_obj; @@ -1566,13 +1543,13 @@ static void parse_class(RzBinFile *bf, RzBinDexClass *c, int class_index, int *m rbin->cb_printf(" Direct methods -\n"); } parse_dex_class_method(bf, c, cls, sym_count, - c->class_data->direct_methods_size, methods, true); + c->class_data->direct_methods_size, methods, true, bob); if (dexdump) { rbin->cb_printf(" Virtual methods -\n"); } parse_dex_class_method(bf, c, cls, sym_count, - c->class_data->virtual_methods_size, methods, false); + c->class_data->virtual_methods_size, methods, false, bob); } if (dexdump) { @@ -1626,17 +1603,10 @@ static bool dex_loadcode(RzBinFile *bf) { rz_list_free(bin->methods_list); return false; } - bin->lines_list = rz_list_newf((RzListFree)free); - if (!bin->lines_list) { - rz_list_free(bin->methods_list); - rz_list_free(bin->imports_list); - return false; - } bin->classes_list = rz_list_newf((RzListFree)rz_bin_class_free); if (!bin->classes_list) { rz_list_free(bin->methods_list); rz_list_free(bin->imports_list); - rz_list_free(bin->lines_list); return false; } @@ -1657,9 +1627,13 @@ static bool dex_loadcode(RzBinFile *bf) { } dexSubsystem = NULL; + RzBinSourceLineInfoBuilder bob; + rz_bin_source_line_info_builder_init(&bob); + if (bin->classes) { ut64 amount = sizeof(int) * bin->header.method_size; if (amount > UT32_MAX || amount < bin->header.method_size) { + rz_bin_source_line_info_builder_fini(&bob); return false; } methods = calloc(1, amount + 1); @@ -1668,9 +1642,12 @@ static bool dex_loadcode(RzBinFile *bf) { if (dexdump) { cb_printf("Class #%zu -\n", i); } - parse_class(bf, c, i, methods, &sym_count); + parse_class(bf, c, i, methods, &sym_count, &bob); } } + + bin->lines = rz_bin_source_line_info_builder_build_and_fini(&bob); + if (methods) { int import_count = 0; int sym_count = bin->methods_list->length; @@ -2083,9 +2060,11 @@ static ut64 size(RzBinFile *bf) { return off + rz_read_le32(u32s); } -static RZ_BORROW RzList *lines(RzBinFile *bf) { +static RzBinSourceLineInfo *lines(RzBinFile *bf) { struct rz_bin_dex_obj_t *dex = bf->o->bin_obj; - return dex->lines_list; + RzBinSourceLineInfo *r = dex->lines; + dex->lines = NULL; + return r; } // iH* @@ -2201,8 +2180,7 @@ RzBinPlugin rz_bin_plugin_dex = { .size = &size, .get_offset = &getoffset, .get_name = &getname, - .dbginfo = &rz_bin_dbginfo_dex, - .lines = &lines, + .lines = lines }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/bin/p/bin_elf.c b/librz/bin/p/bin_elf.c index 47b650b148b..74e8bf4ea5f 100644 --- a/librz/bin/p/bin_elf.c +++ b/librz/bin/p/bin_elf.c @@ -156,7 +156,6 @@ RzBinPlugin rz_bin_plugin_elf = { .libs = &libs, .relocs = &relocs, .patch_relocs = &patch_relocs, - .dbginfo = &rz_bin_dbginfo_elf, .create = &create, .write = &rz_bin_write_elf, .file_type = &get_file_type, diff --git a/librz/bin/p/bin_elf64.c b/librz/bin/p/bin_elf64.c index b3e0a02d77c..2282d0f9220 100644 --- a/librz/bin/p/bin_elf64.c +++ b/librz/bin/p/bin_elf64.c @@ -150,7 +150,6 @@ RzBinPlugin rz_bin_plugin_elf64 = { .libs = &libs, .relocs = &relocs, .patch_relocs = &patch_relocs, - .dbginfo = &rz_bin_dbginfo_elf64, .create = &create, .write = &rz_bin_write_elf64, .get_vaddr = &get_elf_vaddr64, diff --git a/librz/bin/p/bin_symbols.c b/librz/bin/p/bin_symbols.c index bcbb5fdf692..afe1b7241ee 100644 --- a/librz/bin/p/bin_symbols.c +++ b/librz/bin/p/bin_symbols.c @@ -429,6 +429,35 @@ static void header(RzBinFile *bf) { pj_free(pj); } +static RzBinSourceLineInfo *lines(RzBinFile *bf) { + rz_return_val_if_fail(bf && bf->o, NULL); + RzCoreSymCacheElement *element = bf->o->bin_obj; + if (!element || !element->hdr) { + return NULL; + } + RzBinSourceLineInfoBuilder alice; + rz_bin_source_line_info_builder_init(&alice); + if (element->lined_symbols) { + for (size_t i = 0; i < element->hdr->n_lined_symbols; i++) { + RzCoreSymCacheElementLinedSymbol *lsym = &element->lined_symbols[i]; + ut64 addr = rz_coresym_cache_element_pa2va(element, lsym->sym.paddr); + ut32 sz = lsym->sym.size; + rz_bin_source_line_info_builder_push_sample(&alice, addr, lsym->flc.line, lsym->flc.col, lsym->flc.file); + rz_bin_source_line_info_builder_push_sample(&alice, addr + (sz ? sz : 1), 0, 0, NULL); + } + } + if (element->line_info) { + for (size_t i = 0; i < element->hdr->n_line_info; i++) { + RzCoreSymCacheElementLineInfo *info = &element->line_info[i]; + ut64 addr = rz_coresym_cache_element_pa2va(element, info->paddr); + ut32 sz = info->size; + rz_bin_source_line_info_builder_push_sample(&alice, addr, info->flc.line, info->flc.col, info->flc.file); + rz_bin_source_line_info_builder_push_sample(&alice, addr + (sz ? sz : 1), 0, 0, NULL); + } + } + return rz_bin_source_line_info_builder_build_and_fini(&alice); +} + RzBinPlugin rz_bin_plugin_symbols = { .name = "symbols", .desc = "Apple Symbols file", @@ -442,6 +471,7 @@ RzBinPlugin rz_bin_plugin_symbols = { .info = &info, .header = &header, .destroy = &destroy, + .lines = lines }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/core/cbin.c b/librz/core/cbin.c index a3b0cf7d0de..446338d174a 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -1110,165 +1110,114 @@ static int bin_info(RzCore *r, PJ *pj, int mode, ut64 laddr) { static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { rz_return_val_if_fail(core && binfile, false); - RzBinSourceRow *row; - if (!rz_config_get_i(core->config, "bin.dbginfo")) { + if (!rz_config_get_i(core->config, "bin.dbginfo") || !binfile->o) { return false; } - RzBinPlugin *plugin = rz_bin_file_cur_plugin(binfile); - RzList *list = NULL; - RzList *ownlist = NULL; - if (plugin && plugin->lines) { - // list is not cloned to improve speed. avoid use after free - list = plugin->lines(binfile); - } else if (core->bin) { - // TODO: complete and speed-up support for dwarf - RzBinDwarfDebugAbbrev *da = rz_bin_dwarf_parse_abbrev(binfile); - RzBinDwarfDebugInfo *info = da ? rz_bin_dwarf_parse_info(binfile, da) : NULL; - if (mode == RZ_MODE_PRINT) { - if (da) { - rz_core_bin_dwarf_print_abbrev_section(da); - } - if (info) { - rz_core_bin_dwarf_print_debug_info(info); - } + RzBinObject *o = binfile->o; + const RzBinSourceLineInfo *li = NULL; + RzBinDwarfDebugAbbrev *da = rz_bin_dwarf_parse_abbrev(binfile); + RzBinDwarfDebugInfo *info = da ? rz_bin_dwarf_parse_info(binfile, da) : NULL; + if (mode == RZ_MODE_PRINT) { + if (da) { + rz_core_bin_dwarf_print_abbrev_section(da); } - HtUP /**/ *loc_table = rz_bin_dwarf_parse_loc(binfile, core->analysis->bits / 8); - // I suppose there is no reason the parse it for a printing purposes - if (info && mode != RZ_MODE_PRINT) { - /* Should we do this by default? */ - RzAnalysisDwarfContext ctx = { - .info = info, - .loc = loc_table - }; - rz_analysis_dwarf_process_info(core->analysis, &ctx); - } - if (loc_table) { - if (mode == RZ_MODE_PRINT) { - rz_core_bin_dwarf_print_loc(loc_table, core->analysis->bits / 8); - } - rz_bin_dwarf_loc_free(loc_table); + if (info) { + rz_core_bin_dwarf_print_debug_info(info); } + } + HtUP /**/ *loc_table = rz_bin_dwarf_parse_loc(binfile, core->analysis->bits / 8); + // I suppose there is no reason the parse it for a printing purposes + if (info && mode != RZ_MODE_PRINT) { + /* Should we do this by default? */ + RzAnalysisDwarfContext ctx = { + .info = info, + .loc = loc_table + }; + rz_analysis_dwarf_process_info(core->analysis, &ctx); + } + if (loc_table) { if (mode == RZ_MODE_PRINT) { - RzList *aranges = rz_bin_dwarf_parse_aranges(binfile); - if (aranges) { - rz_core_bin_dwarf_print_aranges(aranges); - rz_list_free(aranges); - } + rz_core_bin_dwarf_print_loc(loc_table, core->analysis->bits / 8); } - RzBinDwarfLineInfo *lines = rz_bin_dwarf_parse_line(binfile, info, - RZ_BIN_DWARF_LINE_INFO_MASK_LINES | (mode == RZ_MODE_PRINT ? RZ_BIN_DWARF_LINE_INFO_MASK_OPS : 0)); - rz_bin_dwarf_debug_info_free(info); - if (lines) { - if (mode == RZ_MODE_PRINT) { - rz_core_bin_dwarf_print_line_units(lines->units); - } - // move all produced rows out - list = ownlist = rz_list_newf((RzListFree)rz_bin_source_row_free); - for (size_t i = 0; i < lines->lines->samples_count; i++) { - const RzBinSourceLineSample *s = &lines->lines->samples[i]; - if (!s->file) { - continue; - } - RzBinSourceRow *row = RZ_NEW0(RzBinSourceRow); - row->address = s->address; - row->line = s->line; - row->column = s->column; - row->file = strdup(s->file); - rz_list_push(list, row); - } - rz_bin_dwarf_line_info_free(lines); + rz_bin_dwarf_loc_free(loc_table); + } + if (mode == RZ_MODE_PRINT) { + RzList *aranges = rz_bin_dwarf_parse_aranges(binfile); + if (aranges) { + rz_core_bin_dwarf_print_aranges(aranges); + rz_list_free(aranges); } - rz_bin_dwarf_debug_abbrev_free(da); - - if (IS_MODE_SET(mode) && list && binfile->sdb_addrinfo) { - RzListIter *iter; - rz_list_foreach (list, iter, row) { - if (!row->file || !row->line) { - // !row->file ==> might be theoretically a valid entry but we can't handle it - // !row->line ==> just means "end of previous entry" - continue; - } - char k[32]; - char s[512]; - sdb_set(binfile->sdb_addrinfo, - rz_strf(k, "0x%" PFMT64x, row->address), - rz_strf(s, "%s|%u", row->file, row->line), 0); - } + } + RzBinDwarfLineInfo *lines = rz_bin_dwarf_parse_line(binfile, info, + RZ_BIN_DWARF_LINE_INFO_MASK_LINES | (mode == RZ_MODE_PRINT ? RZ_BIN_DWARF_LINE_INFO_MASK_OPS : 0)); + rz_bin_dwarf_debug_info_free(info); + if (lines) { + if (mode == RZ_MODE_PRINT) { + rz_core_bin_dwarf_print_line_units(lines->units); } + // move all produced rows line info out (TODO: bin loading should do that) + li = o->lines = lines->lines; + lines->lines = NULL; } - if (!list) { + rz_bin_dwarf_debug_abbrev_free(da); + if (!li) { return false; } + if (!IS_MODE_SET(mode)) { + rz_core_bin_print_source_line_info(core, li, mode, pj); + } + return true; +} - rz_cons_break_push(NULL, NULL); +RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, int mode, PJ *pj) { + rz_return_if_fail(core && s && (!IS_MODE_JSON(mode) || pj)); + if (IS_MODE_JSON(mode)) { + bool chopPath = !rz_config_get_i(core->config, "dir.dwarf.abspath"); + char *file = s->file ? strdup(s->file) : NULL; + if (chopPath && file) { + const char *slash = rz_str_lchr(file, '/'); + if (slash) { + memmove(file, slash + 1, strlen(slash)); + } + } + pj_o(pj); + if (file) { + pj_ks(pj, "file", file); + } + pj_kn(pj, "line", (ut64)s->line); + if (s->column) { + pj_kn(pj, "column", (ut64)s->column); + } + pj_kn(pj, "addr", s->address); + pj_end(pj); + free(file); + } else { + rz_cons_printf("0x%08" PFMT64x "\t%s\t", + s->address, s->file ? s->file : "-"); + if (s->line) { + rz_cons_printf("%" PFMT32u "\n", s->line); + } else { + rz_cons_print("-\n"); + } + } +} +RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, int mode, PJ *pj) { + rz_return_if_fail(li && (!IS_MODE_JSON(mode) || pj)); if (IS_MODE_JSON(mode)) { pj_a(pj); } - - //TODO we should need to store all this in sdb, or do a filecontentscache in librz/util - //XXX this whole thing has leaks - RzListIter *iter; - rz_list_foreach (list, iter, row) { + rz_cons_break_push(NULL, NULL); + for (size_t i = 0; i < li->samples_count; i++) { if (rz_cons_is_breaked()) { break; } - if (mode) { - // TODO: use 'Cl' instead of CC - bool chopPath = !rz_config_get_i(core->config, "dir.dwarf.abspath"); - char *file = strdup(row->file); - if (chopPath) { - const char *slash = rz_str_lchr(file, '/'); - if (slash) { - memmove(file, slash + 1, strlen(slash)); - } - } - // TODO: implement internal : if ((mode & RZ_MODE_SET)) - if ((mode & RZ_MODE_SET)) { - // TODO: use CL here.. but its not necessary.. so better not do anything imho - // rz_core_cmdf (core, "CL %s:%d 0x%08"PFMT64x, file, (int)row->line, row->address); -#if 0 - char *cmt = rz_str_newf ("%s:%d %s", file, (int)row->line, line? line: ""); - rz_meta_set_string (core->analysis, RZ_META_TYPE_COMMENT, row->address, cmt); - free (cmt); -#endif - } else if (IS_MODE_JSON(mode)) { - pj_a(pj); - - pj_o(pj); - pj_ks(pj, "file", file); - pj_kn(pj, "line", (ut64)row->line); - if (row->column) { - pj_kn(pj, "column", (ut64)row->column); - } - pj_kn(pj, "addr", row->address); - pj_end(pj); - - pj_end(pj); - } else { - rz_cons_printf("CL %s:%d 0x%08" PFMT64x "\n", - file, (int)row->line, - row->address); - rz_cons_printf("\"CC %s:%d\"@0x%" PFMT64x "\n", - file, row->line, row->address); - } - free(file); - } else { - rz_cons_printf("0x%08" PFMT64x "\t%s\t", - row->address, row->file); - if (row->line) { - rz_cons_printf("%u\n", row->line); - } else { - rz_cons_print("-\n"); - } - } + rz_core_bin_print_source_line_sample(core, &li->samples[i], mode, pj); } + rz_cons_break_pop(); if (IS_MODE_JSON(mode)) { pj_end(pj); } - rz_cons_break_pop(); - rz_list_free(ownlist); - return true; } RZ_API bool rz_core_pdb_info(RzCore *core, const char *file, PJ *pj, int mode) { @@ -1324,43 +1273,55 @@ RZ_API bool rz_core_pdb_info(RzCore *core, const char *file, PJ *pj, int mode) { return true; } -static int srclineCmp(const void *a, const void *b) { - return rz_str_cmp(a, b, -1); +static bool source_file_collect_cb(void *user, const void *k, const void *v) { + RzPVector *r = user; + char *f = strdup(k); + if (f) { + rz_pvector_push(r, f); + } + return true; } static int bin_source(RzCore *r, PJ *pj, int mode) { RzList *final_list = rz_list_new(); RzBinFile *binfile = r->bin->cur; - - if (!binfile) { + if (!binfile || !binfile->o) { bprintf("[Error bin file]\n"); rz_list_free(final_list); return false; } + RzBinSourceLineInfo *li = binfile->o->lines; + if (!li) { + rz_cons_printf("No source info available.\n"); + return true; + } - SdbListIter *iter; - RzListIter *iter2; - char *srcline; - SdbKv *kv; - SdbList *ls = sdb_foreach_list(binfile->sdb_addrinfo, false); - ls_foreach (ls, iter, kv) { - char *v = sdbkv_value(kv); - RzList *list = rz_str_split_list(v, "|", 0); - srcline = rz_list_get_bottom(list); - if (srcline) { - if (!strstr(srcline, "0x")) { - rz_list_append(final_list, srcline); - } + // collect all filenames uniquely + HtPP *files = ht_pp_new0(); + if (!files) { + return false; + } + for (size_t i = 0; i < li->samples_count; i++) { + RzBinSourceLineSample *s = &li->samples[i]; + if (!s->line || !s->file) { + continue; } - rz_list_free(list); + ht_pp_insert(files, s->file, NULL); } + // sort them alphabetically + RzPVector sorter; + rz_pvector_init(&sorter, free); + ht_pp_foreach(files, source_file_collect_cb, &sorter); + rz_pvector_sort(&sorter, (RzPVectorComparator)strcmp); + ht_pp_free(files); + // print them! rz_cons_printf("[Source file]\n"); - RzList *uniqlist = rz_list_uniq(final_list, srclineCmp); - rz_list_foreach (uniqlist, iter2, srcline) { - rz_cons_printf("%s\n", srcline); + void **it; + rz_pvector_foreach (&sorter, it) { + const char *file = *it; + rz_cons_printf("%s\n", file); } - rz_list_free(uniqlist); - rz_list_free(final_list); + rz_pvector_fini(&sorter); return true; } diff --git a/librz/core/cmd_meta.c b/librz/core/cmd_meta.c index 641caf91b65..bd9b7973b1a 100644 --- a/librz/core/cmd_meta.c +++ b/librz/core/cmd_meta.c @@ -24,7 +24,7 @@ static const char *help_msg_C[] = { "CCa", "[+-] [addr] [text]", "add/remove comment at given address", "CCu", " [comment-text] [@addr]", "add unique comment", "CF", "[sz] [fcn-sign..] [@addr]", "function signature", - "CL", "[-][*] [file:line] [addr]", "show or add 'code line' information (bininfo)", + "CL", "[.]", "show source line information (bininfo)", "CS", "[-][space]", "manage meta-spaces to filter comments, etc..", "C[Cthsdmf]", "", "list comments/types/hidden/strings/data/magic/formatted in human friendly form", "C[Cthsdmf]*", "", "list comments/types/hidden/strings/data/magic/formatted in rizin commands", @@ -135,90 +135,6 @@ static const char *help_msg_Cvs[] = { NULL }; -static int remove_meta_offset(RzCore *core, ut64 offset) { - char aoffset[64]; - char *aoffsetptr = sdb_itoa(offset, aoffset, 16); - if (!aoffsetptr) { - eprintf("Failed to convert %" PFMT64x " to a key", offset); - return -1; - } - return sdb_unset(core->bin->cur->sdb_addrinfo, aoffsetptr, 0); -} - -static bool print_meta_offset(RzCore *core, ut64 addr) { - int line, line_old, i; - char file[1024]; - - int ret = rz_bin_addr2line(core->bin, addr, file, sizeof(file) - 1, &line); - if (ret) { - rz_cons_printf("file: %s\nline: %d\n", file, line); - line_old = line; - if (line >= 2) { - line -= 2; - } - if (rz_file_exists(file)) { - for (i = 0; i < 5; i++) { - char *row = rz_file_slurp_line(file, line + i, 0); - if (row) { - rz_cons_printf("%c %.3x %s\n", line + i == line_old ? '>' : ' ', line + i, row); - free(row); - } - } - } else { - eprintf("Cannot open '%s'\n", file); - } - } - return ret; -} - -#if 0 -static int remove_meta_fileline(RzCore *core, const char *file_line) { - return sdb_unset (core->bin->cur->sdb_addrinfo, file_line, 0); -} - -static int print_meta_fileline(RzCore *core, const char *file_line) { - char *meta_info = sdb_get (core->bin->cur->sdb_addrinfo, file_line, 0); - if (meta_info) { - rz_cons_printf ("Meta info %s\n", meta_info); - } else { - rz_cons_printf ("No meta info for %s found\n", file_line); - } - return 0; -} -#endif - -static ut64 filter_offset = UT64_MAX; -static int filter_format = 0; -static size_t filter_count = 0; - -static bool print_addrinfo(void *user, const char *k, const char *v) { - ut64 offset = sdb_atoi(k); - if (!offset || offset == UT64_MAX) { - return true; - } - char *subst = strdup(v); - char *colonpos = strchr(subst, '|'); // XXX keep only : for simplicity? - if (!colonpos) { - colonpos = strchr(subst, ':'); - } - if (!colonpos) { - rz_cons_printf("%s\n", subst); - } - if (colonpos && (filter_offset == UT64_MAX || filter_offset == offset)) { - if (filter_format) { - *colonpos = ':'; - rz_cons_printf("CL %s %s\n", k, subst); - } else { - *colonpos = 0; - rz_cons_printf("file: %s\nline: %s\n", subst, colonpos + 1); - } - filter_count++; - } - free(subst); - - return true; -} - RZ_IPI void rz_core_meta_comment_add(RzCore *core, const char *comment, ut64 addr) { const char *oldcomment = rz_meta_get_string(core->analysis, RZ_META_TYPE_COMMENT, addr); if (!oldcomment || (oldcomment && !strstr(oldcomment, comment))) { @@ -226,114 +142,24 @@ RZ_IPI void rz_core_meta_comment_add(RzCore *core, const char *comment, ut64 add } } -static int cmd_meta_add_fileline(Sdb *s, char *fileline, ut64 offset) { - char aoffset[64]; - char *aoffsetptr = sdb_itoa(offset, aoffset, 16); - - if (!aoffsetptr) { - return -1; - } - if (!sdb_add(s, aoffsetptr, fileline, 0)) { - sdb_set(s, aoffsetptr, fileline, 0); - } - if (!sdb_add(s, fileline, aoffsetptr, 0)) { - sdb_set(s, fileline, aoffsetptr, 0); - } - return 0; -} - static int cmd_meta_lineinfo(RzCore *core, const char *input) { - int ret; - ut64 offset = UT64_MAX; // use this as error value - bool remove = false; - int all = false; - const char *p = input; - char *file_line = NULL; - char *pheap = NULL; - - if (*p == '?') { - eprintf("Usage: CL[.-*?] [addr] [file:line]\n"); - eprintf("or: CL [addr] base64:[string]\n"); - free(pheap); + rz_return_val_if_fail(core && core->bin, 0); + if (!core->bin->cur || !core->bin->cur->o || !core->bin->cur->o->lines) { return 0; } - if (*p == '-') { - p++; - remove = true; - } - if (*p == '.') { - p++; - offset = core->offset; - } - if (*p == ' ') { - p = rz_str_trim_head_ro(p + 1); - char *arg = strchr(p, ' '); - if (!arg) { - offset = rz_num_math(core->num, p); - p = ""; - } - } else if (*p == '*') { - p++; - all = true; - filter_format = '*'; - } else { - filter_format = 0; - } - - if (all) { - if (remove) { - sdb_reset(core->bin->cur->sdb_addrinfo); - } else { - sdb_foreach(core->bin->cur->sdb_addrinfo, print_addrinfo, NULL); - } - free(pheap); + RzBinSourceLineInfo *li = core->bin->cur->o->lines; + if (*input == '?') { + eprintf("Usage: CL[.?]\n"); return 0; } - - p = rz_str_trim_head_ro(p); - char *myp = strdup(p); - char *sp = strchr(myp, ' '); - if (sp) { - *sp = 0; - sp++; - if (offset == UT64_MAX) { - offset = rz_num_math(core->num, myp); + if (*input == '.') { + for (const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(li, core->offset); + s; s = rz_bin_source_line_info_get_next(li, s)) { + rz_core_bin_print_source_line_sample(core, s, 0, NULL); } - - if (!strncmp(sp, "base64:", 7)) { - int len = 0; - ut8 *o = sdb_decode(sp + 7, &len); - if (!o) { - eprintf("Invalid base64\n"); - return 0; - } - sp = pheap = (char *)o; - } - RzBinFile *bf = rz_bin_cur(core->bin); - ret = 0; - if (bf && bf->sdb_addrinfo) { - ret = cmd_meta_add_fileline(bf->sdb_addrinfo, sp, offset); - } else { - eprintf("TODO: Support global SdbAddrinfo or dummy rbinfile to handlee this case\n"); - } - free(file_line); - free(myp); - free(pheap); - return ret; - } - free(myp); - if (remove) { - remove_meta_offset(core, offset); } else { - // taken from r2 // TODO: we should move this addrinfo sdb logic into RzBin.. use HT - filter_offset = offset; - filter_count = 0; - sdb_foreach(core->bin->cur->sdb_addrinfo, print_addrinfo, NULL); - if (filter_count == 0) { - print_meta_offset(core, offset); - } + rz_core_bin_print_source_line_info(core, li, 0, NULL); } - free(pheap); return 0; } diff --git a/librz/include/rz_bin.h b/librz/include/rz_bin.h index 722d005d1c1..117d3eb07f2 100644 --- a/librz/include/rz_bin.h +++ b/librz/include/rz_bin.h @@ -261,7 +261,7 @@ typedef struct rz_bin_object_t { RzList /**/ *classes; HtPP *classes_ht; HtPP *methods_ht; - RzList /**/ *lines; + RzBinSourceLineInfo *lines; HtUP *strings_db; RzList /**/ *mem; //RzBinMem maybe? RzList /* 0, then indicates the line for the given address. - * If == 0, then indicates that the previous record stops here. - * Such a case corresponds for example to what DW_LNE_end_sequence emits in Dwarf. - */ - unsigned int line; - - /** - * If > 0, then indicates the column. - * If == 0, then no column information is known. - */ - unsigned int column; -} RzBinSourceRow; -RZ_API void rz_bin_source_row_free(RzBinSourceRow *row); - typedef struct rz_bin_plugin_t { char *name; char *desc; @@ -543,7 +518,7 @@ typedef struct rz_bin_plugin_t { RzBinAddr *(*binsym)(RzBinFile *bf, int num); RzList /**/ *(*entries)(RzBinFile *bf); RzList /**/ *(*sections)(RzBinFile *bf); - RZ_BORROW RzList /**/ *(*lines)(RzBinFile *bf); + RZ_OWN RzBinSourceLineInfo *(*lines)(RzBinFile *bf); //< only called once on load, ownership is transferred to the caller RzList /**/ *(*symbols)(RzBinFile *bf); RzList /**/ *(*imports)(RzBinFile *bf); RzList /**/ *(*strings)(RzBinFile *bf); @@ -560,7 +535,6 @@ typedef struct rz_bin_plugin_t { void (*header)(RzBinFile *bf); char *(*signature)(RzBinFile *bf, bool json); int (*demangle_type)(const char *str); - struct rz_bin_dbginfo_t *dbginfo; struct rz_bin_write_t *write; char *(*enrich_asm)(RzBinFile *bf, const char *asm_str, int asm_len); int (*get_offset)(RzBinFile *bf, int type, int idx); @@ -724,10 +698,6 @@ typedef struct rz_bin_map_t { char *file; } RzBinMap; -typedef struct rz_bin_dbginfo_t { - bool (*get_line)(RzBinFile *arch, ut64 addr, char *file, int len, int *line); -} RzBinDbgInfo; - typedef struct rz_bin_write_t { ut64 (*scn_resize)(RzBinFile *bf, const char *name, ut64 size); bool (*scn_perms)(RzBinFile *bf, const char *name, int perms); @@ -908,9 +878,9 @@ RZ_API const char *rz_bin_get_meth_flag_string(ut64 flag, bool compact); RZ_API RzBinSection *rz_bin_get_section_at(RzBinObject *o, ut64 off, int va); /* dbginfo.c */ -RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *line); -RZ_API char *rz_bin_addr2text(RzBin *bin, ut64 addr, int origin); -RZ_API char *rz_bin_addr2fileline(RzBin *bin, ut64 addr); +RZ_DEPRECATE RZ_API bool rz_bin_addr2line(RzBin *bin, ut64 addr, char *file, int len, int *line); +RZ_DEPRECATE RZ_API char *rz_bin_addr2text(RzBin *bin, ut64 addr, int origin); + /* bin_write.c */ RZ_API bool rz_bin_wr_addlib(RzBin *bin, const char *lib); RZ_API ut64 rz_bin_wr_scn_resize(RzBin *bin, const char *name, ut64 size); diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 72d185c1f2f..4122b9657e7 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -710,6 +710,9 @@ RZ_API int rz_core_bin_list(RzCore *core, int mode); RZ_API bool rz_core_bin_delete(RzCore *core, ut32 binfile_idx); RZ_API ut64 rz_core_bin_impaddr(RzBin *bin, int va, const char *name); +RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, int mode, PJ *pj); +RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, int mode, PJ *pj); + // bin_dwarf RZ_API void rz_core_bin_dwarf_print_abbrev_section(const RzBinDwarfDebugAbbrev *da); RZ_API void rz_core_bin_dwarf_print_attr_value(const RzBinDwarfAttrValue *val); diff --git a/test/db/abi/compilers/clang b/test/db/abi/compilers/clang index bee35ed5444..f74cbfe8c4f 100644 --- a/test/db/abi/compilers/clang +++ b/test/db/abi/compilers/clang @@ -26,7 +26,7 @@ CMDS=< Date: Thu, 25 Mar 2021 18:47:25 +0100 Subject: [PATCH 4/5] Merge CL and iX into ix --- librz/core/cbin.c | 72 ++---------- librz/core/cmd_info.c | 140 +++++++++++++++++++++++- librz/core/cmd_meta.c | 25 ----- librz/include/rz_core.h | 5 +- test/db/cmd/cmd_i | 125 ++++++++++++++++++++- test/db/cmd/dwarf | 2 +- test/db/formats/dex | 8 +- test/db/formats/mach0/coresymbolication | 12 +- 8 files changed, 281 insertions(+), 108 deletions(-) diff --git a/librz/core/cbin.c b/librz/core/cbin.c index 446338d174a..58d9fb1dfff 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -35,7 +35,6 @@ static RZ_NULLABLE RZ_BORROW const RzList *core_bin_strings(RzCore *r, RzBinFile static void _print_strings(RzCore *r, const RzList *list, PJ *pj, int mode, int va); static bool bin_raw_strings(RzCore *r, PJ *pj, int mode, int va); static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode); -static int bin_source(RzCore *r, PJ *pj, int mode); static int bin_entry(RzCore *r, PJ *pj, int mode, ut64 laddr, int va, bool inifin); static int bin_sections(RzCore *r, PJ *pj, int mode, ut64 laddr, int va, ut64 at, const char *name, const char *chksum, bool print_segments); static int bin_map_sections_to_segments(RzBin *bin, PJ *pj, int mode); @@ -1164,14 +1163,14 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { return false; } if (!IS_MODE_SET(mode)) { - rz_core_bin_print_source_line_info(core, li, mode, pj); + rz_core_bin_print_source_line_info(core, li, IS_MODE_JSON(mode) ? RZ_OUTPUT_MODE_JSON : RZ_OUTPUT_MODE_STANDARD, pj); } return true; } -RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, int mode, PJ *pj) { - rz_return_if_fail(core && s && (!IS_MODE_JSON(mode) || pj)); - if (IS_MODE_JSON(mode)) { +RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, RzOutputMode mode, PJ *pj) { + rz_return_if_fail(core && s && (mode != RZ_OUTPUT_MODE_JSON || pj)); + if (mode == RZ_OUTPUT_MODE_JSON) { bool chopPath = !rz_config_get_i(core->config, "dir.dwarf.abspath"); char *file = s->file ? strdup(s->file) : NULL; if (chopPath && file) { @@ -1202,9 +1201,9 @@ RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSource } } -RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, int mode, PJ *pj) { - rz_return_if_fail(li && (!IS_MODE_JSON(mode) || pj)); - if (IS_MODE_JSON(mode)) { +RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, RzOutputMode mode, PJ *pj) { + rz_return_if_fail(li && (mode != RZ_OUTPUT_MODE_JSON || pj)); + if (mode == RZ_OUTPUT_MODE_JSON) { pj_a(pj); } rz_cons_break_push(NULL, NULL); @@ -1215,7 +1214,7 @@ RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLi rz_core_bin_print_source_line_sample(core, &li->samples[i], mode, pj); } rz_cons_break_pop(); - if (IS_MODE_JSON(mode)) { + if (mode == RZ_OUTPUT_MODE_JSON) { pj_end(pj); } } @@ -1273,58 +1272,6 @@ RZ_API bool rz_core_pdb_info(RzCore *core, const char *file, PJ *pj, int mode) { return true; } -static bool source_file_collect_cb(void *user, const void *k, const void *v) { - RzPVector *r = user; - char *f = strdup(k); - if (f) { - rz_pvector_push(r, f); - } - return true; -} - -static int bin_source(RzCore *r, PJ *pj, int mode) { - RzList *final_list = rz_list_new(); - RzBinFile *binfile = r->bin->cur; - if (!binfile || !binfile->o) { - bprintf("[Error bin file]\n"); - rz_list_free(final_list); - return false; - } - RzBinSourceLineInfo *li = binfile->o->lines; - if (!li) { - rz_cons_printf("No source info available.\n"); - return true; - } - - // collect all filenames uniquely - HtPP *files = ht_pp_new0(); - if (!files) { - return false; - } - for (size_t i = 0; i < li->samples_count; i++) { - RzBinSourceLineSample *s = &li->samples[i]; - if (!s->line || !s->file) { - continue; - } - ht_pp_insert(files, s->file, NULL); - } - // sort them alphabetically - RzPVector sorter; - rz_pvector_init(&sorter, free); - ht_pp_foreach(files, source_file_collect_cb, &sorter); - rz_pvector_sort(&sorter, (RzPVectorComparator)strcmp); - ht_pp_free(files); - // print them! - rz_cons_printf("[Source file]\n"); - void **it; - rz_pvector_foreach (&sorter, it) { - const char *file = *it; - rz_cons_printf("%s\n", file); - } - rz_pvector_fini(&sorter); - return true; -} - static int bin_main(RzCore *r, RzBinFile *binfile, PJ *pj, int mode, int va) { if (!binfile) { return false; @@ -4237,9 +4184,6 @@ RZ_API int rz_core_bin_info(RzCore *core, int action, PJ *pj, int mode, int va, if ((action & RZ_CORE_BIN_ACC_PDB)) { ret &= rz_core_pdb_info(core, core->bin->file, pj, mode); } - if ((action & RZ_CORE_BIN_ACC_SOURCE)) { - ret &= bin_source(core, pj, mode); - } if ((action & RZ_CORE_BIN_ACC_ENTRIES)) { ret &= bin_entry(core, pj, mode, loadaddr, va, false); } diff --git a/librz/core/cmd_info.c b/librz/core/cmd_info.c index 523f7c72af2..ad3a660196f 100644 --- a/librz/core/cmd_info.c +++ b/librz/core/cmd_info.c @@ -58,7 +58,7 @@ static const char *help_msg_i[] = { "iT", "", "File signature", "iV", "", "Display file version info", "iw", "", "try/catch blocks", - "iX", "", "Display source files used (via dwarf)", + "ix", "[.fj?]", "Display source file line info (from debug info)", "iz|izj", "", "Strings in data sections (in JSON/Base64)", "izz", "", "Search for Strings in the whole binary", "izzz", "", "Dump Strings from whole binary to rizin shell (for huge files)", @@ -78,6 +78,14 @@ static const char *help_msg_id[] = { NULL }; +static const char *help_msg_ix[] = { + "Usage: ix", "", "Display source file line info (from debug info)", + "ix[j]", "", "List all source line info available", + "ix.[j]", "", "Show source line info for current address", + "ixf[j]", "", "Show summary of all source files used", + NULL +}; + #define PAIR_WIDTH 9 // TODO: reuse implementation in core/bin.c static void pair(const char *a, const char *b) { @@ -347,6 +355,98 @@ static bool isKnownPackage(const char *cn) { return false; } +static bool source_file_collect_cb(void *user, const void *k, const void *v) { + RzPVector *r = user; + char *f = strdup(k); + if (f) { + rz_pvector_push(r, f); + } + return true; +} + +typedef enum { + PRINT_SOURCE_INFO_LINES_ALL, + PRINT_SOURCE_INFO_LINES_HERE, + PRINT_SOURCE_INFO_FILES +} PrintSourceInfoType; + +static bool print_source_info(RzCore *core, PrintSourceInfoType type, RzOutputMode mode) { + RzBinFile *binfile = core->bin->cur; + if (!binfile || !binfile->o) { + rz_cons_printf("No file loaded.\n"); + return false; + } + RzBinSourceLineInfo *li = binfile->o->lines; + if (!li) { + rz_cons_printf("No source info available.\n"); + return true; + } + PJ *j = NULL; + if (mode == RZ_OUTPUT_MODE_JSON) { + j = pj_new(); + } + switch (type) { + case PRINT_SOURCE_INFO_FILES: { + // collect all filenames uniquely + HtPP *files = ht_pp_new0(); + if (!files) { + return false; + } + for (size_t i = 0; i < li->samples_count; i++) { + RzBinSourceLineSample *s = &li->samples[i]; + if (!s->line || !s->file) { + continue; + } + ht_pp_insert(files, s->file, NULL); + } + // sort them alphabetically + RzPVector sorter; + rz_pvector_init(&sorter, free); + ht_pp_foreach(files, source_file_collect_cb, &sorter); + rz_pvector_sort(&sorter, (RzPVectorComparator)strcmp); + ht_pp_free(files); + // print them! + if (mode == RZ_OUTPUT_MODE_JSON) { + pj_a(j); + void **it; + rz_pvector_foreach (&sorter, it) { + pj_s(j, *it); + } + pj_end(j); + } else { + rz_cons_printf("[Source file]\n"); + void **it; + rz_pvector_foreach (&sorter, it) { + const char *file = *it; + rz_cons_printf("%s\n", file); + } + } + rz_pvector_fini(&sorter); + break; + } + case PRINT_SOURCE_INFO_LINES_ALL: + rz_core_bin_print_source_line_info(core, li, mode, j); + break; + case PRINT_SOURCE_INFO_LINES_HERE: + if (mode == RZ_OUTPUT_MODE_JSON) { + pj_a(j); + } + for (const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(li, core->offset); + s; s = rz_bin_source_line_info_get_next(li, s)) { + rz_core_bin_print_source_line_sample(core, s, mode, j); + } + if (mode == RZ_OUTPUT_MODE_JSON) { + pj_end(j); + } + break; + } + if (mode == RZ_OUTPUT_MODE_JSON) { + rz_cons_println(pj_string(j)); + pj_free(j); + } + return true; +} + RZ_IPI int rz_cmd_info(void *data, const char *input) { RzCore *core = (RzCore *)data; bool newline = rz_cons_is_interactive(); @@ -697,8 +797,40 @@ RZ_IPI int rz_cmd_info(void *data, const char *input) { case 'r': // "ir" RZBININFO("relocs", RZ_CORE_BIN_ACC_RELOCS, NULL); break; - case 'X': // "iX" - RZBININFO("source", RZ_CORE_BIN_ACC_SOURCE, NULL); + case 'x': + newline = false; + switch (*++input) { + case '\0': // "ix" + case ' ': + print_source_info(core, PRINT_SOURCE_INFO_LINES_ALL, RZ_OUTPUT_MODE_STANDARD); + break; + case 'j': // "ixj" + print_source_info(core, PRINT_SOURCE_INFO_LINES_ALL, RZ_OUTPUT_MODE_JSON); + break; + case '.': + if (*++input == 'j') { // "ix.j" + print_source_info(core, PRINT_SOURCE_INFO_LINES_HERE, RZ_OUTPUT_MODE_JSON); + mode = 0; // we do json ourselves here + input++; + } else { // "ix." + print_source_info(core, PRINT_SOURCE_INFO_LINES_HERE, RZ_OUTPUT_MODE_STANDARD); + } + break; + case 'f': + if (*++input == 'j') { // "ixfj" + print_source_info(core, PRINT_SOURCE_INFO_FILES, RZ_OUTPUT_MODE_JSON); + mode = 0; // we do json ourselves here + input++; + } else { // "ixf" + print_source_info(core, PRINT_SOURCE_INFO_FILES, RZ_OUTPUT_MODE_STANDARD); + } + break; + case '?': // "ix?" + default: + rz_core_cmd_help(core, help_msg_ix); + input++; + break; + } break; case 'd': // "id" if (input[1] == 'p') { // "idp" @@ -1110,7 +1242,7 @@ RZ_IPI int rz_cmd_info(void *data, const char *input) { break; } // input can be overwritten like the 'input = " ";' a few lines above - if (input[0] != ' ') { + if (input[0] && input[0] != ' ') { input++; if ((*input == 'j' || *input == 'q') && (input[0] && !input[1])) { break; diff --git a/librz/core/cmd_meta.c b/librz/core/cmd_meta.c index bd9b7973b1a..4bc073e3f20 100644 --- a/librz/core/cmd_meta.c +++ b/librz/core/cmd_meta.c @@ -24,7 +24,6 @@ static const char *help_msg_C[] = { "CCa", "[+-] [addr] [text]", "add/remove comment at given address", "CCu", " [comment-text] [@addr]", "add unique comment", "CF", "[sz] [fcn-sign..] [@addr]", "function signature", - "CL", "[.]", "show source line information (bininfo)", "CS", "[-][space]", "manage meta-spaces to filter comments, etc..", "C[Cthsdmf]", "", "list comments/types/hidden/strings/data/magic/formatted in human friendly form", "C[Cthsdmf]*", "", "list comments/types/hidden/strings/data/magic/formatted in rizin commands", @@ -142,27 +141,6 @@ RZ_IPI void rz_core_meta_comment_add(RzCore *core, const char *comment, ut64 add } } -static int cmd_meta_lineinfo(RzCore *core, const char *input) { - rz_return_val_if_fail(core && core->bin, 0); - if (!core->bin->cur || !core->bin->cur->o || !core->bin->cur->o->lines) { - return 0; - } - RzBinSourceLineInfo *li = core->bin->cur->o->lines; - if (*input == '?') { - eprintf("Usage: CL[.?]\n"); - return 0; - } - if (*input == '.') { - for (const RzBinSourceLineSample *s = rz_bin_source_line_info_get_first_at(li, core->offset); - s; s = rz_bin_source_line_info_get_next(li, s)) { - rz_core_bin_print_source_line_sample(core, s, 0, NULL); - } - } else { - rz_core_bin_print_source_line_info(core, li, 0, NULL); - } - return 0; -} - static int cmd_meta_comment(RzCore *core, const char *input) { ut64 addr = core->offset; switch (input[1]) { @@ -836,9 +814,6 @@ RZ_IPI int rz_cmd_meta(void *data, const char *input) { rz_meta_print_list_at(core->analysis, core->offset, 0); break; } - case 'L': // "CL" - cmd_meta_lineinfo(core, input + 1); - break; case 'C': // "CC" cmd_meta_comment(core, input); break; diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index 4122b9657e7..c371edd142b 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -710,8 +710,8 @@ RZ_API int rz_core_bin_list(RzCore *core, int mode); RZ_API bool rz_core_bin_delete(RzCore *core, ut32 binfile_idx); RZ_API ut64 rz_core_bin_impaddr(RzBin *bin, int va, const char *name); -RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, int mode, PJ *pj); -RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, int mode, PJ *pj); +RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, RzOutputMode mode, PJ *pj); +RZ_API void rz_core_bin_print_source_line_info(RzCore *core, const RzBinSourceLineInfo *li, RzOutputMode mode, PJ *pj); // bin_dwarf RZ_API void rz_core_bin_dwarf_print_abbrev_section(const RzBinDwarfDebugAbbrev *da); @@ -759,7 +759,6 @@ RZ_API void rz_core_recover_vars(RzCore *core, RzAnalysisFunction *fcn, bool arg #define RZ_CORE_BIN_ACC_RESOURCES 0x100000 #define RZ_CORE_BIN_ACC_INITFINI 0x200000 #define RZ_CORE_BIN_ACC_SEGMENTS 0x400000 -#define RZ_CORE_BIN_ACC_SOURCE 0x800000 #define RZ_CORE_BIN_ACC_HASHES 0x10000000 #define RZ_CORE_BIN_ACC_TRYCATCH 0x20000000 #define RZ_CORE_BIN_ACC_SECTIONS_MAPPING 0x40000000 diff --git a/test/db/cmd/cmd_i b/test/db/cmd/cmd_i index a76bb886a2b..9b8909314e3 100644 --- a/test/db/cmd/cmd_i +++ b/test/db/cmd/cmd_i @@ -4251,7 +4251,7 @@ RUN NAME=iX FILE=bins/elf/analysis/dwarf_load -CMDS=iX +CMDS=ixf EXPECT=< Date: Thu, 25 Mar 2021 18:53:37 +0100 Subject: [PATCH 5/5] Split bin_dwarf in Setting and Printing --- librz/core/cbin.c | 65 ++++++++++++++++++++++++++--------------- librz/include/rz_core.h | 1 + 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/librz/core/cbin.c b/librz/core/cbin.c index 58d9fb1dfff..9f68dabacc8 100644 --- a/librz/core/cbin.c +++ b/librz/core/cbin.c @@ -34,7 +34,6 @@ static RZ_NULLABLE RZ_BORROW const RzList *core_bin_strings(RzCore *r, RzBinFile *file); static void _print_strings(RzCore *r, const RzList *list, PJ *pj, int mode, int va); static bool bin_raw_strings(RzCore *r, PJ *pj, int mode, int va); -static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode); static int bin_entry(RzCore *r, PJ *pj, int mode, ut64 laddr, int va, bool inifin); static int bin_sections(RzCore *r, PJ *pj, int mode, ut64 laddr, int va, ut64 at, const char *name, const char *chksum, bool print_segments); static int bin_map_sections_to_segments(RzBin *bin, PJ *pj, int mode); @@ -378,7 +377,7 @@ RZ_API int rz_core_bin_apply_all_info(RzCore *r, RzBinFile *binfile) { rz_core_bin_apply_strings(r, binfile); rz_core_bin_apply_config(r, binfile); rz_core_bin_apply_main(r, binfile, va); - bin_dwarf(r, binfile, NULL, RZ_MODE_SET); + rz_core_bin_apply_dwarf(r, binfile); bin_entry(r, NULL, RZ_MODE_SET, loadaddr, va, false); bin_sections(r, NULL, RZ_MODE_SET, loadaddr, va, UT64_MAX, NULL, NULL, false); bin_sections(r, NULL, RZ_MODE_SET, loadaddr, va, UT64_MAX, NULL, NULL, true); @@ -510,6 +509,40 @@ RZ_API bool rz_core_bin_apply_main(RzCore *r, RzBinFile *binfile, bool va) { return true; } +RZ_API bool rz_core_bin_apply_dwarf(RzCore *core, RzBinFile *binfile) { + rz_return_val_if_fail(core && binfile, false); + if (!rz_config_get_i(core->config, "bin.dbginfo") || !binfile->o) { + return false; + } + RzBinObject *o = binfile->o; + const RzBinSourceLineInfo *li = NULL; + RzBinDwarfDebugAbbrev *da = rz_bin_dwarf_parse_abbrev(binfile); + RzBinDwarfDebugInfo *info = da ? rz_bin_dwarf_parse_info(binfile, da) : NULL; + HtUP /**/ *loc_table = rz_bin_dwarf_parse_loc(binfile, core->analysis->bits / 8); + if (info) { + RzAnalysisDwarfContext ctx = { + .info = info, + .loc = loc_table + }; + rz_analysis_dwarf_process_info(core->analysis, &ctx); + } + if (loc_table) { + rz_bin_dwarf_loc_free(loc_table); + } + RzBinDwarfLineInfo *lines = rz_bin_dwarf_parse_line(binfile, info, RZ_BIN_DWARF_LINE_INFO_MASK_LINES); + rz_bin_dwarf_debug_info_free(info); + if (lines) { + // move all produced rows line info out (TODO: bin loading should do that) + li = o->lines = lines->lines; + lines->lines = NULL; + } + rz_bin_dwarf_debug_abbrev_free(da); + if (!li) { + return false; + } + return true; +} + RZ_API int rz_core_bin_set_cur(RzCore *core, RzBinFile *binfile) { if (!core->bin) { return false; @@ -1112,8 +1145,6 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { if (!rz_config_get_i(core->config, "bin.dbginfo") || !binfile->o) { return false; } - RzBinObject *o = binfile->o; - const RzBinSourceLineInfo *li = NULL; RzBinDwarfDebugAbbrev *da = rz_bin_dwarf_parse_abbrev(binfile); RzBinDwarfDebugInfo *info = da ? rz_bin_dwarf_parse_info(binfile, da) : NULL; if (mode == RZ_MODE_PRINT) { @@ -1125,15 +1156,6 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { } } HtUP /**/ *loc_table = rz_bin_dwarf_parse_loc(binfile, core->analysis->bits / 8); - // I suppose there is no reason the parse it for a printing purposes - if (info && mode != RZ_MODE_PRINT) { - /* Should we do this by default? */ - RzAnalysisDwarfContext ctx = { - .info = info, - .loc = loc_table - }; - rz_analysis_dwarf_process_info(core->analysis, &ctx); - } if (loc_table) { if (mode == RZ_MODE_PRINT) { rz_core_bin_dwarf_print_loc(loc_table, core->analysis->bits / 8); @@ -1147,6 +1169,7 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { rz_list_free(aranges); } } + bool ret = false; RzBinDwarfLineInfo *lines = rz_bin_dwarf_parse_line(binfile, info, RZ_BIN_DWARF_LINE_INFO_MASK_LINES | (mode == RZ_MODE_PRINT ? RZ_BIN_DWARF_LINE_INFO_MASK_OPS : 0)); rz_bin_dwarf_debug_info_free(info); @@ -1154,18 +1177,14 @@ static bool bin_dwarf(RzCore *core, RzBinFile *binfile, PJ *pj, int mode) { if (mode == RZ_MODE_PRINT) { rz_core_bin_dwarf_print_line_units(lines->units); } - // move all produced rows line info out (TODO: bin loading should do that) - li = o->lines = lines->lines; - lines->lines = NULL; + if (lines->lines) { + ret = true; + rz_core_bin_print_source_line_info(core, lines->lines, IS_MODE_JSON(mode) ? RZ_OUTPUT_MODE_JSON : RZ_OUTPUT_MODE_STANDARD, pj); + } + rz_bin_dwarf_line_info_free(lines); } rz_bin_dwarf_debug_abbrev_free(da); - if (!li) { - return false; - } - if (!IS_MODE_SET(mode)) { - rz_core_bin_print_source_line_info(core, li, IS_MODE_JSON(mode) ? RZ_OUTPUT_MODE_JSON : RZ_OUTPUT_MODE_STANDARD, pj); - } - return true; + return ret; } RZ_API void rz_core_bin_print_source_line_sample(RzCore *core, const RzBinSourceLineSample *s, RzOutputMode mode, PJ *pj) { diff --git a/librz/include/rz_core.h b/librz/include/rz_core.h index c371edd142b..0bc45154e27 100644 --- a/librz/include/rz_core.h +++ b/librz/include/rz_core.h @@ -700,6 +700,7 @@ RZ_API bool rz_core_bin_raise(RzCore *core, ut32 bfid); RZ_API bool rz_core_bin_apply_strings(RzCore *r, RzBinFile *binfile); RZ_API bool rz_core_bin_apply_config(RzCore *r, RzBinFile *binfile); RZ_API bool rz_core_bin_apply_main(RzCore *r, RzBinFile *binfile, bool va); +RZ_API bool rz_core_bin_apply_dwarf(RzCore *core, RzBinFile *binfile); RZ_API int rz_core_bin_apply_all_info(RzCore *r, RzBinFile *binfile); RZ_API int rz_core_bin_set_by_fd(RzCore *core, ut64 bin_fd); RZ_API int rz_core_bin_set_by_name(RzCore *core, const char *name);