diff --git a/addr2line.c b/addr2line.c index 7956cc457a..1226090ffc 100644 --- a/addr2line.c +++ b/addr2line.c @@ -144,7 +144,7 @@ void *alloca(); #define DW_LNE_define_file 0x03 #define DW_LNE_set_discriminator 0x04 /* DWARF4 */ -#define kprintf(...) fprintf(stderr, "" __VA_ARGS__) +#define kprintf(...) fprintf(errout, "" __VA_ARGS__) typedef struct line_info { const char *dirname; @@ -254,7 +254,7 @@ sleb128(const char **p) } static const char * -get_nth_dirname(unsigned long dir, const char *p) +get_nth_dirname(unsigned long dir, const char *p, FILE *errout) { if (!dir--) { return ""; @@ -271,10 +271,14 @@ get_nth_dirname(unsigned long dir, const char *p) return p; } -static const char *parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index); +static const char *parse_ver5_debug_line_header( + const char *p, int idx, uint8_t format, + obj_info_t *obj, const char **out_path, + uint64_t *out_directory_index, FILE *errout); static void -fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories, const char *filenames, line_info_t *line, obj_info_t *obj) +fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories, + const char *filenames, line_info_t *line, obj_info_t *obj, FILE *errout) { int i; const char *p = filenames; @@ -283,9 +287,9 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di if (version >= 5) { const char *path; uint64_t directory_index = -1; - parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index); + parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index, errout); line->filename = path; - parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL); + parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL, errout); line->dirname = path; } else { @@ -307,7 +311,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di if (i == file) { line->filename = filename; - line->dirname = get_nth_dirname(dir, include_directories); + line->dirname = get_nth_dirname(dir, include_directories, errout); } } } @@ -316,7 +320,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di static void fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line, uint8_t format, uint16_t version, const char *include_directories, const char *filenames, - obj_info_t *obj, line_info_t *lines, int offset) + obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) { int i; addr += obj->base_addr - obj->vmaddr; @@ -325,7 +329,7 @@ fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line, /* We assume one line code doesn't result >100 bytes of native code. We may want more reliable way eventually... */ if (addr < a && a < addr + 100) { - fill_filename(file, format, version, include_directories, filenames, &lines[i], obj); + fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout); lines[i].line = line; } } @@ -350,7 +354,7 @@ struct LineNumberProgramHeader { }; static int -parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header) +parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header, FILE *errout) { const char *p = *pp; header->unit_length = *(uint32_t *)p; @@ -396,7 +400,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr if (header->version >= 5) { header->include_directories = p; - p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL); + p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL, errout); header->filenames = p; } else { @@ -423,7 +427,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr static int parse_debug_line_cu(int num_traces, void **traces, const char **debug_line, - obj_info_t *obj, line_info_t *lines, int offset) + obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) { const char *p = (const char *)*debug_line; struct LineNumberProgramHeader header; @@ -440,7 +444,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line, /* int epilogue_begin = 0; */ /* unsigned int isa = 0; */ - if (parse_debug_line_header(obj, &p, &header)) + if (parse_debug_line_header(obj, &p, &header, errout)) return -1; is_stmt = header.default_is_stmt; @@ -451,7 +455,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line, header.version, \ header.include_directories, \ header.filenames, \ - obj, lines, offset); \ + obj, lines, offset, errout); \ /*basic_block = prologue_end = epilogue_begin = 0;*/ \ } while (0) @@ -551,11 +555,11 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line, static int parse_debug_line(int num_traces, void **traces, const char *debug_line, unsigned long size, - obj_info_t *obj, line_info_t *lines, int offset) + obj_info_t *obj, line_info_t *lines, int offset, FILE *errout) { const char *debug_line_end = debug_line + size; while (debug_line < debug_line_end) { - if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset)) + if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout)) return -1; } if (debug_line != debug_line_end) { @@ -568,7 +572,7 @@ parse_debug_line(int num_traces, void **traces, /* read file and fill lines */ static uintptr_t fill_lines(int num_traces, void **traces, int check_debuglink, - obj_info_t **objp, line_info_t *lines, int offset); + obj_info_t **objp, line_info_t *lines, int offset, FILE *errout); static void append_obj(obj_info_t **objp) @@ -596,7 +600,7 @@ append_obj(obj_info_t **objp) // check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug" static void follow_debuglink(const char *debuglink, int num_traces, void **traces, - obj_info_t **objp, line_info_t *lines, int offset) + obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) { static const char global_debug_dir[] = "/usr/lib/debug"; const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1; @@ -622,13 +626,13 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces, o2 = *objp; o2->base_addr = o1->base_addr; o2->path = o1->path; - fill_lines(num_traces, traces, 0, objp, lines, offset); + fill_lines(num_traces, traces, 0, objp, lines, offset, errout); } // check the path pattern of "/usr/lib/debug/.build-id/ab/cdef1234.debug" static void follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_traces, void **traces, - obj_info_t **objp, line_info_t *lines, int offset) + obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) { static const char global_debug_dir[] = "/usr/lib/debug/.build-id/"; const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1; @@ -653,7 +657,7 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr o2 = *objp; o2->base_addr = o1->base_addr; o2->path = o1->path; - fill_lines(num_traces, traces, 0, objp, lines, offset); + fill_lines(num_traces, traces, 0, objp, lines, offset, errout); } #endif @@ -1079,13 +1083,13 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader) } static int -di_read_debug_line_cu(DebugInfoReader *reader) +di_read_debug_line_cu(DebugInfoReader *reader, FILE *errout) { const char *p; struct LineNumberProgramHeader header; p = (const char *)reader->debug_line_cu_end; - if (parse_debug_line_header(reader->obj, &p, &header)) + if (parse_debug_line_header(reader->obj, &p, &header, errout)) return -1; reader->debug_line_cu_end = (char *)header.cu_end; @@ -1186,7 +1190,7 @@ debug_info_reader_read_addr_value_member(DebugInfoReader *reader, DebugInfoValue static bool -debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v) +debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v, FILE *errout) { switch (form) { case DW_FORM_addr: @@ -1369,7 +1373,7 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa /* find abbrev in current compilation unit */ static const char * -di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) +di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout) { const char *p; if (abbrev_number < ABBREV_TABLE_SIZE) { @@ -1394,7 +1398,7 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number) #if 0 static void -hexdump0(const unsigned char *p, size_t n) +hexdump0(const unsigned char *p, size_t n, FILE *errout) { size_t i; kprintf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); @@ -1415,10 +1419,10 @@ hexdump0(const unsigned char *p, size_t n) kprintf("\n"); } } -#define hexdump(p,n) hexdump0((const unsigned char *)p, n) +#define hexdump(p,n,e) hexdump0((const unsigned char *)p, n, e) static void -div_inspect(DebugInfoValue *v) +div_inspect(DebugInfoValue *v, FILE *errout) { switch (v->type) { case VAL_uint: @@ -1432,14 +1436,14 @@ div_inspect(DebugInfoValue *v) break; case VAL_data: kprintf("%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size); - hexdump(v->as.ptr, 16); + hexdump(v->as.ptr, 16, errout); break; } } #endif static DIE * -di_read_die(DebugInfoReader *reader, DIE *die) +di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout) { uint64_t abbrev_number = uleb128(&reader->p); if (abbrev_number == 0) { @@ -1447,7 +1451,7 @@ di_read_die(DebugInfoReader *reader, DIE *die) return NULL; } - if (!(reader->q = di_find_abbrev(reader, abbrev_number))) return NULL; + if (!(reader->q = di_find_abbrev(reader, abbrev_number, errout))) return NULL; die->pos = reader->p - reader->obj->debug_info.ptr - 1; die->tag = (int)uleb128(&reader->q); /* tag */ @@ -1459,26 +1463,26 @@ di_read_die(DebugInfoReader *reader, DIE *die) } static DebugInfoValue * -di_read_record(DebugInfoReader *reader, DebugInfoValue *vp) +di_read_record(DebugInfoReader *reader, DebugInfoValue *vp, FILE *errout) { uint64_t at = uleb128(&reader->q); uint64_t form = uleb128(&reader->q); if (!at || !form) return NULL; vp->at = at; vp->form = form; - if (!debug_info_reader_read_value(reader, form, vp)) return NULL; + if (!debug_info_reader_read_value(reader, form, vp, errout)) return NULL; return vp; } static bool -di_skip_records(DebugInfoReader *reader) +di_skip_records(DebugInfoReader *reader, FILE *errout) { for (;;) { DebugInfoValue v = {{0}}; uint64_t at = uleb128(&reader->q); uint64_t form = uleb128(&reader->q); if (!at || !form) return true; - if (!debug_info_reader_read_value(reader, form, &v)) return false; + if (!debug_info_reader_read_value(reader, form, &v, errout)) return false; } } @@ -1491,7 +1495,8 @@ typedef struct addr_header { } addr_header_t; static bool -addr_header_init(obj_info_t *obj, addr_header_t *header) { +addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout) +{ const char *p = obj->debug_addr.ptr; header->ptr = p; @@ -1536,7 +1541,8 @@ typedef struct rnglists_header { } rnglists_header_t; static bool -rnglists_header_init(obj_info_t *obj, rnglists_header_t *header) { +rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout) +{ const char *p = obj->debug_rnglists.ptr; if (!p) return true; @@ -1603,7 +1609,7 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v, addr_header_t *addr_header, uint64_ } static uint64_t -read_dw_form_addr(DebugInfoReader *reader, const char **ptr) +read_dw_form_addr(DebugInfoReader *reader, const char **ptr, FILE *errout) { const char *p = *ptr; *ptr = p + reader->address_size; @@ -1615,7 +1621,7 @@ read_dw_form_addr(DebugInfoReader *reader, const char **ptr) } static uintptr_t -ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header) +ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header, FILE *errout) { if (ptr->high_pc_set) { if (ptr->ranges_set || !ptr->low_pc_set) { @@ -1668,15 +1674,15 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h to = (uintptr_t)base + uleb128(&p); break; case DW_RLE_base_address: - base = read_dw_form_addr(reader, &p); + base = read_dw_form_addr(reader, &p, errout); base_valid = true; break; case DW_RLE_start_end: - from = (uintptr_t)read_dw_form_addr(reader, &p); - to = (uintptr_t)read_dw_form_addr(reader, &p); + from = (uintptr_t)read_dw_form_addr(reader, &p, errout); + to = (uintptr_t)read_dw_form_addr(reader, &p, errout); break; case DW_RLE_start_length: - from = (uintptr_t)read_dw_form_addr(reader, &p); + from = (uintptr_t)read_dw_form_addr(reader, &p, errout); to = from + uleb128(&p); break; } @@ -1710,7 +1716,7 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h #if 0 static void -ranges_inspect(DebugInfoReader *reader, ranges_t *ptr) +ranges_inspect(DebugInfoReader *reader, ranges_t *ptr, FILE *errout) { if (ptr->high_pc_set) { if (ptr->ranges_set || !ptr->low_pc_set) { @@ -1740,7 +1746,7 @@ ranges_inspect(DebugInfoReader *reader, ranges_t *ptr) #endif static int -di_read_cu(DebugInfoReader *reader) +di_read_cu(DebugInfoReader *reader, FILE *errout) { uint64_t unit_length; uint16_t version; @@ -1775,15 +1781,15 @@ di_read_cu(DebugInfoReader *reader) reader->level = 0; di_read_debug_abbrev_cu(reader); - if (di_read_debug_line_cu(reader)) return -1; + if (di_read_debug_line_cu(reader, errout)) return -1; do { DIE die; - if (!di_read_die(reader, &die)) continue; + if (!di_read_die(reader, &die, errout)) continue; if (die.tag != DW_TAG_compile_unit) { - if (!di_skip_records(reader)) return -1; + if (!di_skip_records(reader, errout)) return -1; break; } @@ -1795,7 +1801,7 @@ di_read_cu(DebugInfoReader *reader) /* enumerate abbrev */ for (;;) { DebugInfoValue v = {{0}}; - if (!di_read_record(reader, &v)) break; + if (!di_read_record(reader, &v, errout)) break; switch (v.at) { case DW_AT_low_pc: // clang may output DW_AT_addr_base after DW_AT_low_pc. @@ -1821,7 +1827,7 @@ di_read_cu(DebugInfoReader *reader) case VAL_addr: { addr_header_t header = {0}; - if (!addr_header_init(reader->obj, &header)) return -1; + if (!addr_header_init(reader->obj, &header, errout)) return -1; reader->current_low_pc = read_addr(&header, reader->current_addr_base, low_pc.as.addr_idx); } break; @@ -1832,7 +1838,7 @@ di_read_cu(DebugInfoReader *reader) } static void -read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line) +read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line, FILE *errout) { const char *p = reader->p; const char *q = reader->q; @@ -1857,12 +1863,12 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o default: goto finish; } - if (!di_read_die(reader, &die)) goto finish; + if (!di_read_die(reader, &die, errout)) goto finish; /* enumerate abbrev */ for (;;) { DebugInfoValue v = {{0}}; - if (!di_read_record(reader, &v)) break; + if (!di_read_record(reader, &v, errout)) break; switch (v.at) { case DW_AT_name: line->sname = get_cstr_value(&v); @@ -1878,25 +1884,26 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o static bool debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, - line_info_t *lines, int offset) { + line_info_t *lines, int offset, FILE *errout) +{ addr_header_t addr_header = {0}; - if (!addr_header_init(reader->obj, &addr_header)) return false; + if (!addr_header_init(reader->obj, &addr_header, errout)) return false; rnglists_header_t rnglists_header = {0}; - if (!rnglists_header_init(reader->obj, &rnglists_header)) return false; + if (!rnglists_header_init(reader->obj, &rnglists_header, errout)) return false; while (reader->p < reader->cu_end) { DIE die; ranges_t ranges = {0}; line_info_t line = {0}; - if (!di_read_die(reader, &die)) continue; + if (!di_read_die(reader, &die, errout)) continue; /* kprintf("%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */ if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) { skip_die: - if (!di_skip_records(reader)) return false; + if (!di_skip_records(reader, errout)) return false; continue; } @@ -1904,15 +1911,15 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, for (;;) { DebugInfoValue v = {{0}}; /* ptrdiff_t pos = reader->p - reader->p0; */ - if (!di_read_record(reader, &v)) break; + if (!di_read_record(reader, &v, errout)) break; /* kprintf("\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */ - /* div_inspect(&v); */ + /* div_inspect(&v, errout); */ switch (v.at) { case DW_AT_name: line.sname = get_cstr_value(&v); break; case DW_AT_call_file: - fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj); + fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj, errout); break; case DW_AT_call_line: line.line = (int)v.as.uint64; @@ -1928,16 +1935,16 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, /* 1 or 3 */ break; /* goto skip_die; */ case DW_AT_abstract_origin: - read_abstract_origin(reader, v.form, v.as.uint64, &line); + read_abstract_origin(reader, v.form, v.as.uint64, &line, errout); break; /* goto skip_die; */ } } - /* ranges_inspect(reader, &ranges); */ + /* ranges_inspect(reader, &ranges, errout); */ /* kprintf("%d:%tx: %x ",__LINE__,diepos,die.tag); */ for (int i=offset; i < num_traces; i++) { uintptr_t addr = (uintptr_t)traces[i]; uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr; - uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header); + uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header, errout); if (saddr == UINTPTR_MAX) return false; if (saddr) { /* kprintf("%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */ @@ -1976,7 +1983,10 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces, // // It records DW_LNCT_path and DW_LNCT_directory_index at the index "idx". static const char * -parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index) { +parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, + obj_info_t *obj, const char **out_path, + uint64_t *out_directory_index, FILE *errout) +{ int i, j; int entry_format_count = *(uint8_t *)p++; const char *entry_format = p; @@ -1996,7 +2006,7 @@ parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t DebugInfoValue v = {{0}}; unsigned long dw_lnct = uleb128(&format); unsigned long dw_form = uleb128(&format); - if (!debug_info_reader_read_value(&reader, dw_form, &v)) return 0; + if (!debug_info_reader_read_value(&reader, dw_form, &v, errout)) return 0; if (dw_lnct == 1 /* DW_LNCT_path */ && v.type == VAL_cstr && out_path) *out_path = v.as.ptr + v.off; if (dw_lnct == 2 /* DW_LNCT_directory_index */ && v.type == VAL_uint && out_directory_index) @@ -2041,7 +2051,7 @@ fail: /* read file and fill lines */ static uintptr_t fill_lines(int num_traces, void **traces, int check_debuglink, - obj_info_t **objp, line_info_t *lines, int offset) + obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) { int i, j; char *shstr; @@ -2202,8 +2212,8 @@ fill_lines(int num_traces, void **traces, int check_debuglink, i = 0; while (reader.p < reader.pend) { /* kprintf("%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */ - if (di_read_cu(&reader)) goto use_symtab; - if (!debug_info_read(&reader, num_traces, traces, lines, offset)) + if (di_read_cu(&reader, errout)) goto use_symtab; + if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout)) goto use_symtab; } } @@ -2244,14 +2254,14 @@ use_symtab: if (gnu_debuglink_shdr && check_debuglink) { follow_debuglink(file + gnu_debuglink_shdr->sh_offset, num_traces, traces, - objp, lines, offset); + objp, lines, offset, errout); } if (note_gnu_build_id && check_debuglink) { ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset); const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz; follow_debuglink_build_id(build_id, nhdr->n_descsz, num_traces, traces, - objp, lines, offset); + objp, lines, offset, errout); } goto finish; } @@ -2259,7 +2269,7 @@ use_symtab: if (parse_debug_line(num_traces, traces, obj->debug_line.ptr, obj->debug_line.size, - obj, lines, offset) == -1) + obj, lines, offset, errout) == -1) goto fail; finish: @@ -2271,7 +2281,7 @@ fail: /* read file and fill lines */ static uintptr_t fill_lines(int num_traces, void **traces, int check_debuglink, - obj_info_t **objp, line_info_t *lines, int offset) + obj_info_t **objp, line_info_t *lines, int offset, FILE *errout) { # ifdef __LP64__ # define LP(x) x##_64 @@ -2472,8 +2482,8 @@ found_mach_header: DebugInfoReader reader; debug_info_reader_init(&reader, obj); while (reader.p < reader.pend) { - if (di_read_cu(&reader)) goto fail; - if (!debug_info_read(&reader, num_traces, traces, lines, offset)) + if (di_read_cu(&reader, errout)) goto fail; + if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout)) goto fail; } } @@ -2481,7 +2491,7 @@ found_mach_header: if (parse_debug_line(num_traces, traces, obj->debug_line.ptr, obj->debug_line.size, - obj, lines, offset) == -1) + obj, lines, offset, errout) == -1) goto fail; return dladdr_fbase; @@ -2542,7 +2552,7 @@ main_exe_path(void) #endif static void -print_line0(line_info_t *line, void *address) +print_line0(line_info_t *line, void *address, FILE *errout) { uintptr_t addr = (uintptr_t)address; uintptr_t d = addr - line->saddr; @@ -2583,16 +2593,16 @@ print_line0(line_info_t *line, void *address) } static void -print_line(line_info_t *line, void *address) +print_line(line_info_t *line, void *address, FILE *errout) { - print_line0(line, address); + print_line0(line, address, errout); if (line->next) { - print_line(line->next, NULL); + print_line(line->next, NULL, errout); } } void -rb_dump_backtrace_with_lines(int num_traces, void **traces) +rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout) { int i; /* async-signal unsafe */ @@ -2611,7 +2621,7 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces) memcpy(main_path, binary_filename, len+1); append_obj(&obj); obj->path = main_path; - addr = fill_lines(num_traces, traces, 1, &obj, lines, -1); + addr = fill_lines(num_traces, traces, 1, &obj, lines, -1, errout); if (addr != (uintptr_t)-1) { dladdr_fbases[0] = (void *)addr; } @@ -2648,7 +2658,7 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces) lines[i].saddr = (uintptr_t)info.dli_saddr; } strlcpy(binary_filename, path, PATH_MAX); - if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (uintptr_t)-1) + if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1) break; } next_line: @@ -2657,7 +2667,7 @@ next_line: /* output */ for (i = 0; i < num_traces; i++) { - print_line(&lines[i], traces[i]); + print_line(&lines[i], traces[i], errout); /* FreeBSD's backtrace may show _start and so on */ if (lines[i].sname && strcmp("main", lines[i].sname) == 0) diff --git a/addr2line.h b/addr2line.h index f09b665800..ff8e476b92 100644 --- a/addr2line.h +++ b/addr2line.h @@ -12,8 +12,10 @@ #if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)) +#include + void -rb_dump_backtrace_with_lines(int num_traces, void **traces); +rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout); #endif /* USE_ELF */ diff --git a/error.c b/error.c index cd031120e2..3aac9a3d87 100644 --- a/error.c +++ b/error.c @@ -757,7 +757,7 @@ bug_report_end(FILE *out) FILE *out = bug_report_file(file, line); \ if (out) { \ bug_report_begin(out, fmt); \ - rb_vm_bugreport(ctx); \ + rb_vm_bugreport(ctx, out); \ bug_report_end(out); \ } \ } while (0) \ @@ -766,7 +766,7 @@ bug_report_end(FILE *out) FILE *out = bug_report_file(file, line); \ if (out) { \ bug_report_begin_valist(out, fmt, args); \ - rb_vm_bugreport(ctx); \ + rb_vm_bugreport(ctx, out); \ bug_report_end(out); \ } \ } while (0) \ @@ -881,7 +881,7 @@ rb_assert_failure(const char *file, int line, const char *name, const char *expr if (name) fprintf(out, "%s:", name); fprintf(out, "%s\n%s\n\n", expr, rb_dynamic_description); preface_dump(out); - rb_vm_bugreport(NULL); + rb_vm_bugreport(NULL, out); bug_report_end(out); die(); } @@ -3256,7 +3256,7 @@ rb_fatal(const char *fmt, ...) /* The thread has no GVL. Object allocation impossible (cant run GC), * thus no message can be printed out. */ fprintf(stderr, "[FATAL] rb_fatal() outside of GVL\n"); - rb_print_backtrace(); + rb_print_backtrace(stderr); die(); } diff --git a/gc.c b/gc.c index 95d4cf8cd1..2993e56a36 100644 --- a/gc.c +++ b/gc.c @@ -7798,7 +7798,7 @@ check_children_i(const VALUE child, void *ptr) if (check_rvalue_consistency_force(child, FALSE) != 0) { fprintf(stderr, "check_children_i: %s has error (referenced from %s)", obj_info(child), obj_info(data->parent)); - rb_print_backtrace(); /* C backtrace will help to debug */ + rb_print_backtrace(stderr); /* C backtrace will help to debug */ data->err_count++; } @@ -9118,7 +9118,7 @@ rb_gc_register_address(VALUE *addr) if (0 && !SPECIAL_CONST_P(obj)) { rb_warn("Object is assigned to registering address already: %"PRIsVALUE, rb_obj_class(obj)); - rb_print_backtrace(); + rb_print_backtrace(stderr); } } diff --git a/internal/vm.h b/internal/vm.h index a89af3d9a9..571cf73c52 100644 --- a/internal/vm.h +++ b/internal/vm.h @@ -95,7 +95,7 @@ int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID i void rb_clear_constant_cache(void); /* vm_dump.c */ -void rb_print_backtrace(void); +void rb_print_backtrace(FILE *); /* vm_backtrace.c */ VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval); @@ -103,7 +103,7 @@ VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval) VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec); VALUE rb_make_backtrace(void); -void rb_backtrace_print_as_bugreport(void); +void rb_backtrace_print_as_bugreport(FILE*); int rb_backtrace_p(VALUE obj); VALUE rb_backtrace_to_str_ary(VALUE obj); VALUE rb_backtrace_to_location_ary(VALUE obj); diff --git a/vm.c b/vm.c index 792d1e5a5e..e325cf3d9a 100644 --- a/vm.c +++ b/vm.c @@ -3542,7 +3542,7 @@ extern size_t rb_gc_stack_maxsize; static VALUE sdr(VALUE self) { - rb_vm_bugreport(NULL); + rb_vm_bugreport(NULL, stderr); return Qnil; } diff --git a/vm_backtrace.c b/vm_backtrace.c index 42debfba3d..34ebde0f0b 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -71,7 +71,7 @@ calc_pos(const rb_iseq_t *iseq, const VALUE *pc, int *lineno, int *node_id) #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP) else { /* SDR() is not possible; that causes infinite loop. */ - rb_print_backtrace(); + rb_print_backtrace(stderr); __builtin_trap(); } #endif @@ -1003,31 +1003,38 @@ vm_backtrace_print(FILE *fp) &arg); } +struct oldbt_bugreport_arg { + FILE *fp; + int count; +}; + static void oldbt_bugreport(void *arg, VALUE file, int line, VALUE method) { + struct oldbt_bugreport_arg *p = arg; + FILE *fp = p->fp; const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file); - if (!*(int *)arg) { - fprintf(stderr, "-- Ruby level backtrace information " + if (!p->count) { + fprintf(fp, "-- Ruby level backtrace information " "----------------------------------------\n"); - *(int *)arg = 1; + p->count = 1; } if (NIL_P(method)) { - fprintf(stderr, "%s:%d:in unknown method\n", filename, line); + fprintf(fp, "%s:%d:in unknown method\n", filename, line); } else { - fprintf(stderr, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method)); + fprintf(fp, "%s:%d:in `%s'\n", filename, line, RSTRING_PTR(method)); } } void -rb_backtrace_print_as_bugreport(void) +rb_backtrace_print_as_bugreport(FILE *fp) { struct oldbt_arg arg; - int i = 0; + struct oldbt_bugreport_arg barg = {fp, 0}; arg.func = oldbt_bugreport; - arg.data = (int *)&i; + arg.data = &barg; backtrace_each(GET_EC(), oldbt_init, diff --git a/vm_core.h b/vm_core.h index f3e5a04f72..d600b0a153 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1678,13 +1678,13 @@ VALUE rb_proc_alloc(VALUE klass); VALUE rb_proc_dup(VALUE self); /* for debug */ -extern void rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); -extern void rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc); -extern void rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp); +extern void rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); +extern void rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *); +extern void rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *); -#define SDR() rb_vmdebug_stack_dump_raw(GET_EC(), GET_EC()->cfp) -#define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_EC(), (cfp)) -void rb_vm_bugreport(const void *); +#define SDR() rb_vmdebug_stack_dump_raw(GET_EC(), GET_EC()->cfp, stderr) +#define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_EC(), (cfp), stderr) +void rb_vm_bugreport(const void *, FILE *); typedef void (*ruby_sighandler_t)(int); RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 4, 5) NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const void *, const char *fmt, ...)); diff --git a/vm_dump.c b/vm_dump.c index b9f4e098a0..a2e5c384be 100644 --- a/vm_dump.c +++ b/vm_dump.c @@ -47,7 +47,7 @@ const char *rb_method_type_name(rb_method_type_t type); int ruby_on_ci; static void -control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp) +control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { ptrdiff_t pc = -1; ptrdiff_t ep = cfp->ep - ec->vm_stack; @@ -140,30 +140,30 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c line = -1; } - fprintf(stderr, "c:%04"PRIdPTRDIFF" ", + fprintf(errout, "c:%04"PRIdPTRDIFF" ", ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size) - cfp)); if (pc == -1) { - fprintf(stderr, "p:---- "); + fprintf(errout, "p:---- "); } else { - fprintf(stderr, "p:%04"PRIdPTRDIFF" ", pc); + fprintf(errout, "p:%04"PRIdPTRDIFF" ", pc); } - fprintf(stderr, "s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack); - fprintf(stderr, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); - fprintf(stderr, "%-6s", magic); + fprintf(errout, "s:%04"PRIdPTRDIFF" ", cfp->sp - ec->vm_stack); + fprintf(errout, ep_in_heap == ' ' ? "e:%06"PRIdPTRDIFF" " : "E:%06"PRIxPTRDIFF" ", ep % 10000); + fprintf(errout, "%-6s", magic); if (line) { - fprintf(stderr, " %s", posbuf); + fprintf(errout, " %s", posbuf); } if (VM_FRAME_FINISHED_P(cfp)) { - fprintf(stderr, " [FINISH]"); + fprintf(errout, " [FINISH]"); } if (0) { - fprintf(stderr, " \t"); - fprintf(stderr, "iseq: %-24s ", iseq_name); - fprintf(stderr, "self: %-24s ", selfstr); - fprintf(stderr, "%-1s ", biseq_name); + fprintf(errout, " \t"); + fprintf(errout, "iseq: %-24s ", iseq_name); + fprintf(errout, "self: %-24s ", selfstr); + fprintf(errout, "%-1s ", biseq_name); } - fprintf(stderr, "\n"); + fprintf(errout, "\n"); // additional information for CI machines if (ruby_on_ci) { @@ -171,26 +171,26 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c if (me) { if (IMEMO_TYPE_P(me, imemo_ment)) { - fprintf(stderr, " me:\n"); - fprintf(stderr, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type)); - fprintf(stderr, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner)); + fprintf(errout, " me:\n"); + fprintf(errout, " called_id: %s, type: %s\n", rb_id2name(me->called_id), rb_method_type_name(me->def->type)); + fprintf(errout, " owner class: %s\n", rb_raw_obj_info(buff, 0x100, me->owner)); if (me->owner != me->defined_class) { - fprintf(stderr, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class)); + fprintf(errout, " defined_class: %s\n", rb_raw_obj_info(buff, 0x100, me->defined_class)); } } else { - fprintf(stderr, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me)); + fprintf(errout, " me is corrupted (%s)\n", rb_raw_obj_info(buff, 0x100, (VALUE)me)); } } - fprintf(stderr, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self)); + fprintf(errout, " self: %s\n", rb_raw_obj_info(buff, 0x100, cfp->self)); if (iseq) { if (ISEQ_BODY(iseq)->local_table_size > 0) { - fprintf(stderr, " lvars:\n"); + fprintf(errout, " lvars:\n"); for (unsigned int i=0; ilocal_table_size; i++) { const VALUE *argv = cfp->ep - ISEQ_BODY(cfp->iseq)->local_table_size - VM_ENV_DATA_SIZE + 1; - fprintf(stderr, " %s: %s\n", + fprintf(errout, " %s: %s\n", rb_id2name(ISEQ_BODY(iseq)->local_table[i]), rb_raw_obj_info(buff, 0x100, argv[i])); } @@ -200,83 +200,83 @@ control_frame_dump(const rb_execution_context_t *ec, const rb_control_frame_t *c } void -rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp) +rb_vmdebug_stack_dump_raw(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { #if 0 VALUE *sp = cfp->sp; const VALUE *ep = cfp->ep; VALUE *p, *st, *t; - fprintf(stderr, "-- stack frame ------------\n"); + fprintf(errout, "-- stack frame ------------\n"); for (p = st = ec->vm_stack; p < sp; p++) { - fprintf(stderr, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); + fprintf(errout, "%04ld (%p): %08"PRIxVALUE, (long)(p - st), p, *p); t = (VALUE *)*p; if (ec->vm_stack <= t && t < sp) { - fprintf(stderr, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack)); + fprintf(errout, " (= %ld)", (long)((VALUE *)GC_GUARDED_PTR_REF((VALUE)t) - ec->vm_stack)); } if (p == ep) - fprintf(stderr, " <- ep"); + fprintf(errout, " <- ep"); - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } #endif - fprintf(stderr, "-- Control frame information " + fprintf(errout, "-- Control frame information " "-----------------------------------------------\n"); while ((void *)cfp < (void *)(ec->vm_stack + ec->vm_stack_size)) { - control_frame_dump(ec, cfp); + control_frame_dump(ec, cfp, errout); cfp++; } - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } void rb_vmdebug_stack_dump_raw_current(void) { const rb_execution_context_t *ec = GET_EC(); - rb_vmdebug_stack_dump_raw(ec, ec->cfp); + rb_vmdebug_stack_dump_raw(ec, ec->cfp, stderr); } void -rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep) +rb_vmdebug_env_dump_raw(const rb_env_t *env, const VALUE *ep, FILE *errout) { unsigned int i; - fprintf(stderr, "-- env --------------------\n"); + fprintf(errout, "-- env --------------------\n"); while (env) { - fprintf(stderr, "--\n"); + fprintf(errout, "--\n"); for (i = 0; i < env->env_size; i++) { - fprintf(stderr, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]); - if (&env->env[i] == ep) fprintf(stderr, " <- ep"); - fprintf(stderr, "\n"); + fprintf(errout, "%04d: %08"PRIxVALUE" (%p)", i, env->env[i], (void *)&env->env[i]); + if (&env->env[i] == ep) fprintf(errout, " <- ep"); + fprintf(errout, "\n"); } env = rb_vm_env_prev_env(env); } - fprintf(stderr, "---------------------------\n"); + fprintf(errout, "---------------------------\n"); } void -rb_vmdebug_proc_dump_raw(rb_proc_t *proc) +rb_vmdebug_proc_dump_raw(rb_proc_t *proc, FILE *errout) { const rb_env_t *env; char *selfstr; VALUE val = rb_inspect(vm_block_self(&proc->block)); selfstr = StringValueCStr(val); - fprintf(stderr, "-- proc -------------------\n"); - fprintf(stderr, "self: %s\n", selfstr); + fprintf(errout, "-- proc -------------------\n"); + fprintf(errout, "self: %s\n", selfstr); env = VM_ENV_ENVVAL_PTR(vm_block_ep(&proc->block)); - rb_vmdebug_env_dump_raw(env, vm_block_ep(&proc->block)); + rb_vmdebug_env_dump_raw(env, vm_block_ep(&proc->block), errout); } void -rb_vmdebug_stack_dump_th(VALUE thval) +rb_vmdebug_stack_dump_th(VALUE thval, FILE *errout) { rb_thread_t *target_th = rb_thread_ptr(thval); - rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp); + rb_vmdebug_stack_dump_raw(target_th->ec, target_th->ec->cfp, errout); } #if VMDEBUG > 2 @@ -295,7 +295,7 @@ vm_base_ptr(const rb_control_frame_t *cfp) } static void -vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *cfp) +vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { int i, argc = 0, local_table_size = 0; VALUE rstr; @@ -321,17 +321,17 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c { const VALUE *ptr = ep - local_table_size; - control_frame_dump(ec, cfp); + control_frame_dump(ec, cfp, errout); for (i = 0; i < argc; i++) { rstr = rb_inspect(*ptr); - fprintf(stderr, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), - (void *)ptr++); + fprintf(errout, " arg %2d: %8s (%p)\n", i, StringValueCStr(rstr), + (void *)ptr++); } for (; i < local_table_size - 1; i++) { rstr = rb_inspect(*ptr); - fprintf(stderr, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), - (void *)ptr++); + fprintf(errout, " local %2d: %8s (%p)\n", i, StringValueCStr(rstr), + (void *)ptr++); } ptr = vm_base_ptr(cfp); @@ -347,13 +347,13 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c rstr = rb_inspect(*ptr); break; } - fprintf(stderr, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), + fprintf(errout, " stack %2d: %8s (%"PRIdPTRDIFF")\n", i, StringValueCStr(rstr), (ptr - ec->vm_stack)); } } else if (VM_FRAME_FINISHED_P(cfp)) { if (ec->vm_stack + ec->vm_stack_size > (VALUE *)(cfp + 1)) { - vm_stack_dump_each(ec, cfp + 1); + vm_stack_dump_each(ec, cfp + 1, errout); } else { /* SDR(); */ @@ -366,7 +366,7 @@ vm_stack_dump_each(const rb_execution_context_t *ec, const rb_control_frame_t *c #endif void -rb_vmdebug_debug_print_register(const rb_execution_context_t *ec) +rb_vmdebug_debug_print_register(const rb_execution_context_t *ec, FILE *errout) { rb_control_frame_t *cfp = ec->cfp; ptrdiff_t pc = -1; @@ -382,18 +382,18 @@ rb_vmdebug_debug_print_register(const rb_execution_context_t *ec) } cfpi = ((rb_control_frame_t *)(ec->vm_stack + ec->vm_stack_size)) - cfp; - fprintf(stderr, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", + fprintf(errout, " [PC] %04"PRIdPTRDIFF", [SP] %04"PRIdPTRDIFF", [EP] %04"PRIdPTRDIFF", [CFP] %04"PRIdPTRDIFF"\n", pc, (cfp->sp - ec->vm_stack), ep, cfpi); } void -rb_vmdebug_thread_dump_regs(VALUE thval) +rb_vmdebug_thread_dump_regs(VALUE thval, FILE *errout) { - rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec); + rb_vmdebug_debug_print_register(rb_thread_ptr(thval)->ec, errout); } void -rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc) +rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, const VALUE *_pc, FILE *errout) { const rb_iseq_t *iseq = cfp->iseq; @@ -416,27 +416,27 @@ rb_vmdebug_debug_print_pre(const rb_execution_context_t *ec, const rb_control_fr } #if VMDEBUG > 3 - fprintf(stderr, " (1)"); - rb_vmdebug_debug_print_register(ec); + fprintf(errout, " (1)"); + rb_vmdebug_debug_print_register(errout, ec); #endif } void -rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp) +rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, FILE *errout) { #if VMDEBUG > 9 - SDR2(cfp); + rb_vmdebug_stack_dump_raw(ec, cfp, errout); #endif #if VMDEBUG > 3 - fprintf(stderr, " (2)"); - rb_vmdebug_debug_print_register(ec); + fprintf(errout, " (2)"); + rb_vmdebug_debug_print_register(errout, ec); #endif /* stack_dump_raw(ec, cfp); */ #if VMDEBUG > 2 /* stack_dump_thobj(ec); */ - vm_stack_dump_each(ec, ec->cfp); + vm_stack_dump_each(ec, ec->cfp, errout); printf ("--------------------------------------------------------------\n"); @@ -444,14 +444,14 @@ rb_vmdebug_debug_print_post(const rb_execution_context_t *ec, const rb_control_f } VALUE -rb_vmdebug_thread_dump_state(VALUE self) +rb_vmdebug_thread_dump_state(FILE *errout, VALUE self) { rb_thread_t *th = rb_thread_ptr(self); rb_control_frame_t *cfp = th->ec->cfp; - fprintf(stderr, "Thread state dump:\n"); - fprintf(stderr, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); - fprintf(stderr, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep); + fprintf(errout, "Thread state dump:\n"); + fprintf(errout, "pc : %p, sp : %p\n", (void *)cfp->pc, (void *)cfp->sp); + fprintf(errout, "cfp: %p, ep : %p\n", (void *)cfp, (void *)cfp->ep); return Qnil; } @@ -664,6 +664,11 @@ typedef void *PGET_MODULE_BASE_ROUTINE64; typedef void *PTRANSLATE_ADDRESS_ROUTINE64; # endif +struct dump_thead_arg { + DWORD tid; + FILE *errout; +}; + static void dump_thread(void *arg) { @@ -675,7 +680,8 @@ dump_thread(void *arg) BOOL (WINAPI *pSymFromAddr)(HANDLE, DWORD64, DWORD64 *, SYMBOL_INFO *); BOOL (WINAPI *pSymGetLineFromAddr64)(HANDLE, DWORD64, DWORD *, IMAGEHLP_LINE64 *); HANDLE (WINAPI *pOpenThread)(DWORD, BOOL, DWORD); - DWORD tid = *(DWORD *)arg; + DWORD tid = ((struct dump_thead_arg *)arg)->tid; + FILE *errout = ((struct dump_thead_arg *)arg)->errout; HANDLE ph; HANDLE th; @@ -740,16 +746,16 @@ dump_thread(void *arg) info->MaxNameLen = MAX_SYM_NAME; if (pSymFromAddr(ph, addr, &displacement, info)) { if (GetModuleFileName((HANDLE)(uintptr_t)pSymGetModuleBase64(ph, addr), libpath, sizeof(libpath))) - fprintf(stderr, "%s", libpath); - fprintf(stderr, "(%s+0x%"PRI_64_PREFIX"x)", + fprintf(errout, "%s", libpath); + fprintf(errout, "(%s+0x%"PRI_64_PREFIX"x)", info->Name, displacement); } - fprintf(stderr, " [0x%p]", (void *)(VALUE)addr); + fprintf(errout, " [0x%p]", (void *)(VALUE)addr); memset(&line, 0, sizeof(line)); line.SizeOfStruct = sizeof(line); if (pSymGetLineFromAddr64(ph, addr, &tmp, &line)) - fprintf(stderr, " %s:%lu", line.FileName, line.LineNumber); - fprintf(stderr, "\n"); + fprintf(errout, " %s:%lu", line.FileName, line.LineNumber); + fprintf(errout, "\n"); } } @@ -764,27 +770,30 @@ dump_thread(void *arg) #endif void -rb_print_backtrace(void) +rb_print_backtrace(FILE *errout) { #if USE_BACKTRACE #define MAX_NATIVE_TRACE 1024 static void *trace[MAX_NATIVE_TRACE]; int n = (int)backtrace(trace, MAX_NATIVE_TRACE); #if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)) && defined(HAVE_DLADDR) && !defined(__sparc) - rb_dump_backtrace_with_lines(n, trace); + rb_dump_backtrace_with_lines(n, trace, errout); #else char **syms = backtrace_symbols(trace, n); if (syms) { int i; for (i=0; igregs[REG_##reg], #reg, col_count, 80)) +# define dump_machine_register(reg) (col_count = print_machine_register(errout, mctx->gregs[REG_##reg], #reg, col_count, 80)) # elif defined(__aarch64__) || defined(__arm__) || defined(__riscv) || defined(__loongarch64) -# define dump_machine_register(reg, regstr) (col_count = print_machine_register(reg, regstr, col_count, 80)) +# define dump_machine_register(reg, regstr) (col_count = print_machine_register(errout, reg, regstr, col_count, 80)) # endif #elif defined __APPLE__ # if defined(__aarch64__) -# define dump_machine_register(reg, regstr) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), regstr, col_count, 80)) +# define dump_machine_register(reg, regstr) (col_count = print_machine_register(errout, mctx->MCTX_SS_REG(reg), regstr, col_count, 80)) # else -# define dump_machine_register(reg) (col_count = print_machine_register(mctx->MCTX_SS_REG(reg), #reg, col_count, 80)) +# define dump_machine_register(reg) (col_count = print_machine_register(errout, mctx->MCTX_SS_REG(reg), #reg, col_count, 80)) # endif #endif #ifdef dump_machine_register static int -print_machine_register(size_t reg, const char *reg_name, int col_count, int max_col) +print_machine_register(FILE *errout, size_t reg, const char *reg_name, int col_count, int max_col) { int ret; char buf[64]; @@ -818,21 +827,21 @@ print_machine_register(size_t reg, const char *reg_name, int col_count, int max_ ret = snprintf(buf, sizeof(buf), " %3.3s: 0x%.*" PRIxSIZE, reg_name, size_width, reg); if (col_count + ret > max_col) { - fputs("\n", stderr); + fputs("\n", errout); col_count = 0; } col_count += ret; - fputs(buf, stderr); + fputs(buf, errout); return col_count; } static void -rb_dump_machine_register(const ucontext_t *ctx) +rb_dump_machine_register(FILE *errout, const ucontext_t *ctx) { int col_count = 0; if (!ctx) return; - fprintf(stderr, "-- Machine register context " + fprintf(errout, "-- Machine register context " "------------------------------------------------\n"); # if defined __linux__ @@ -1025,14 +1034,14 @@ rb_dump_machine_register(const ucontext_t *ctx) # endif } # endif - fprintf(stderr, "\n\n"); + fprintf(errout, "\n\n"); } #else -# define rb_dump_machine_register(ctx) ((void)0) +# define rb_dump_machine_register(errout, ctx) ((void)0) #endif /* dump_machine_register */ void -rb_vm_bugreport(const void *ctx) +rb_vm_bugreport(const void *ctx, FILE *errout) { const char *cmd = getenv("RUBY_ON_BUG"); if (cmd) { @@ -1049,7 +1058,7 @@ rb_vm_bugreport(const void *ctx) { static bool crashing = false; if (crashing) { - fprintf(stderr, "Crashed while printing bug report\n"); + fprintf(errout, "Crashed while printing bug report\n"); return; } crashing = true; @@ -1067,32 +1076,32 @@ rb_vm_bugreport(const void *ctx) const rb_execution_context_t *ec = rb_current_execution_context(false); if (vm && ec) { - SDR(); - rb_backtrace_print_as_bugreport(); - fputs("\n", stderr); + rb_vmdebug_stack_dump_raw(ec, ec->cfp, errout); + rb_backtrace_print_as_bugreport(errout); + fputs("\n", errout); // If we get here, hopefully things are intact enough that // we can read these two numbers. It is an estimate because // we are reading without synchronization. - fprintf(stderr, "-- Threading information " + fprintf(errout, "-- Threading information " "---------------------------------------------------\n"); - fprintf(stderr, "Total ractor count: %u\n", vm->ractor.cnt); - fprintf(stderr, "Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt); - fputs("\n", stderr); + fprintf(errout, "Total ractor count: %u\n", vm->ractor.cnt); + fprintf(errout, "Ruby thread count for this ractor: %u\n", rb_ec_ractor_ptr(ec)->threads.cnt); + fputs("\n", errout); } - rb_dump_machine_register(ctx); + rb_dump_machine_register(errout, ctx); #if USE_BACKTRACE || defined(_WIN32) - fprintf(stderr, "-- C level backtrace information " + fprintf(errout, "-- C level backtrace information " "-------------------------------------------\n"); - rb_print_backtrace(); + rb_print_backtrace(errout); - fprintf(stderr, "\n"); + fprintf(errout, "\n"); #endif /* USE_BACKTRACE */ if (other_runtime_info || vm) { - fprintf(stderr, "-- Other runtime information " + fprintf(errout, "-- Other runtime information " "-----------------------------------------------\n\n"); } if (vm && !rb_during_gc()) { @@ -1105,16 +1114,16 @@ rb_vm_bugreport(const void *ctx) name = vm->progname; if (name) { - fprintf(stderr, "* Loaded script: %.*s\n", + fprintf(errout, "* Loaded script: %.*s\n", LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } if (vm->loaded_features) { - fprintf(stderr, "* Loaded features:\n\n"); + fprintf(errout, "* Loaded features:\n\n"); for (i=0; iloaded_features); i++) { name = RARRAY_AREF(vm->loaded_features, i); if (RB_TYPE_P(name, T_STRING)) { - fprintf(stderr, " %4d %.*s\n", i, + fprintf(errout, " %4d %.*s\n", i, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else if (RB_TYPE_P(name, T_CLASS) || RB_TYPE_P(name, T_MODULE)) { @@ -1122,26 +1131,26 @@ rb_vm_bugreport(const void *ctx) "class" : "module"; name = rb_search_class_path(rb_class_real(name)); if (!RB_TYPE_P(name, T_STRING)) { - fprintf(stderr, " %4d %s:\n", i, type); + fprintf(errout, " %4d %s:\n", i, type); continue; } - fprintf(stderr, " %4d %s:%.*s\n", i, type, + fprintf(errout, " %4d %s:%.*s\n", i, type, LIMITED_NAME_LENGTH(name), RSTRING_PTR(name)); } else { VALUE klass = rb_search_class_path(rb_obj_class(name)); if (!RB_TYPE_P(klass, T_STRING)) { - fprintf(stderr, " %4d #<%p:%p>\n", i, + fprintf(errout, " %4d #<%p:%p>\n", i, (void *)CLASS_OF(name), (void *)name); continue; } - fprintf(stderr, " %4d #<%.*s:%p>\n", i, + fprintf(errout, " %4d #<%.*s:%p>\n", i, LIMITED_NAME_LENGTH(klass), RSTRING_PTR(klass), (void *)name); } } } - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } { @@ -1149,17 +1158,17 @@ rb_vm_bugreport(const void *ctx) { FILE *fp = fopen(PROC_MAPS_NAME, "r"); if (fp) { - fprintf(stderr, "* Process memory map:\n\n"); + fprintf(errout, "* Process memory map:\n\n"); while (!feof(fp)) { char buff[0x100]; size_t rn = fread(buff, 1, 0x100, fp); - if (fwrite(buff, 1, rn, stderr) != rn) + if (fwrite(buff, 1, rn, errout) != rn) break; } fclose(fp); - fprintf(stderr, "\n\n"); + fprintf(errout, "\n\n"); } } #endif /* __linux__ */ @@ -1173,14 +1182,14 @@ rb_vm_bugreport(const void *ctx) mib[2] = KERN_PROC_PID; mib[3] = getpid(); if (sysctl(mib, MIB_KERN_PROC_PID_LEN, &kp, &len, NULL, 0) == -1) { - perror("sysctl"); + fprintf(errout, "sysctl: %s\n", strerror(errno)); } else { struct procstat *prstat = procstat_open_sysctl(); - fprintf(stderr, "* Process memory map:\n\n"); + fprintf(errout, "* Process memory map:\n\n"); procstat_vm(prstat, &kp); procstat_close(prstat); - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } #endif /* __FreeBSD__ */ #ifdef __APPLE__ @@ -1190,7 +1199,7 @@ rb_vm_bugreport(const void *ctx) mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT; natural_t depth = 0; - fprintf(stderr, "* Process memory map:\n\n"); + fprintf(errout, "* Process memory map:\n\n"); while (1) { if (vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_t)&map, &count) != KERN_SUCCESS) { @@ -1202,17 +1211,17 @@ rb_vm_bugreport(const void *ctx) depth++; } else { - fprintf(stderr, "%lx-%lx %s%s%s", addr, (addr+size), + fprintf(errout, "%lx-%lx %s%s%s", addr, (addr+size), ((map.protection & VM_PROT_READ) != 0 ? "r" : "-"), ((map.protection & VM_PROT_WRITE) != 0 ? "w" : "-"), ((map.protection & VM_PROT_EXECUTE) != 0 ? "x" : "-")); #ifdef HAVE_LIBPROC_H char buff[PATH_MAX]; if (proc_regionfilename(getpid(), addr, buff, sizeof(buff)) > 0) { - fprintf(stderr, " %s", buff); + fprintf(errout, " %s", buff); } #endif - fprintf(stderr, "\n"); + fprintf(errout, "\n"); } addr += size; @@ -1227,14 +1236,15 @@ rb_vmdebug_stack_dump_all_threads(void) { rb_thread_t *th = NULL; rb_ractor_t *r = GET_RACTOR(); + FILE *errout = stderr; // TODO: now it only shows current ractor ccan_list_for_each(&r->threads.set, th, lt_node) { #ifdef NON_SCALAR_THREAD_ID - fprintf(stderr, "th: %p, native_id: N/A\n", th); + fprintf(errout, "th: %p, native_id: N/A\n", th); #else - fprintf(stderr, "th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id); + fprintf(errout, "th: %p, native_id: %p\n", (void *)th, (void *)(uintptr_t)th->nt->thread_id); #endif - rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp); + rb_vmdebug_stack_dump_raw(th->ec, th->ec->cfp, errout); } }