зеркало из https://github.com/github/ruby.git
* addr2line.c: added to show source filename and line number of
functions in backtrace. [ruby-dev:42625] a patch from shinichiro.h <shinichiro.hamaji AT gmail.com> * addr2line.h: ditto. * common.mk: add addr2line.$(OBJEXT). * configure.in: check dl_iterate_phdr. * vm_dump.c (rb_vm_bugreport): use rb_dump_backtrace_with_lines in addr2line.c when the binary is ELF. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29940 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
f8f3585416
Коммит
086301ac73
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
Fri Nov 26 12:21:20 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
|
* addr2line.c: added to show source filename and line number of
|
||||||
|
functions in backtrace. [ruby-dev:42625]
|
||||||
|
a patch from shinichiro.h <shinichiro.hamaji AT gmail.com>
|
||||||
|
|
||||||
|
* addr2line.h: ditto.
|
||||||
|
|
||||||
|
* common.mk: add addr2line.$(OBJEXT).
|
||||||
|
|
||||||
|
* configure.in: check dl_iterate_phdr.
|
||||||
|
|
||||||
|
* vm_dump.c (rb_vm_bugreport): use rb_dump_backtrace_with_lines in
|
||||||
|
addr2line.c when the binary is ELF.
|
||||||
|
|
||||||
Fri Nov 26 12:12:50 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
Fri Nov 26 12:12:50 2010 NARUSE, Yui <naruse@ruby-lang.org>
|
||||||
|
|
||||||
* regcomp.c (setup_tree): restart setup_tree() for a node whose
|
* regcomp.c (setup_tree): restart setup_tree() for a node whose
|
||||||
|
|
|
@ -0,0 +1,534 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
addr2line.h -
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
|
||||||
|
Copyright (C) 2010 Shinichiro Hamaji
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "addr2line.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __ELF__
|
||||||
|
|
||||||
|
#include <elf.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_DL_ITERATE_PHDR
|
||||||
|
# ifndef _GNU_SOURCE
|
||||||
|
# define _GNU_SOURCE
|
||||||
|
# endif
|
||||||
|
# include <link.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DW_LNS_copy 0x01
|
||||||
|
#define DW_LNS_advance_pc 0x02
|
||||||
|
#define DW_LNS_advance_line 0x03
|
||||||
|
#define DW_LNS_set_file 0x04
|
||||||
|
#define DW_LNS_set_column 0x05
|
||||||
|
#define DW_LNS_negate_stmt 0x06
|
||||||
|
#define DW_LNS_set_basic_block 0x07
|
||||||
|
#define DW_LNS_const_add_pc 0x08
|
||||||
|
#define DW_LNS_fixed_advance_pc 0x09
|
||||||
|
#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
|
||||||
|
#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
|
||||||
|
#define DW_LNS_set_isa 0x0c /* DWARF3 */
|
||||||
|
|
||||||
|
/* Line number extended opcode name. */
|
||||||
|
#define DW_LNE_end_sequence 0x01
|
||||||
|
#define DW_LNE_set_address 0x02
|
||||||
|
#define DW_LNE_define_file 0x03
|
||||||
|
#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
|
||||||
|
|
||||||
|
# if SIZEOF_VOIDP == 8
|
||||||
|
# define ElfW(x) Elf64##_##x
|
||||||
|
# else
|
||||||
|
# define ElfW(x) Elf32##_##x
|
||||||
|
# endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *dirname;
|
||||||
|
const char *filename;
|
||||||
|
int line;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
void *mapped;
|
||||||
|
size_t mapped_size;
|
||||||
|
unsigned long base_addr;
|
||||||
|
} line_info_t;
|
||||||
|
|
||||||
|
/* Avoid consuming stack as this module may be used from signal handler */
|
||||||
|
static char binary_filename[PATH_MAX];
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
uleb128(char **p) {
|
||||||
|
unsigned long r = 0;
|
||||||
|
int s = 0;
|
||||||
|
for (;;) {
|
||||||
|
unsigned char b = *(unsigned char *)(*p)++;
|
||||||
|
if (b < 0x80) {
|
||||||
|
r += b << s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r += (b & 0x7f) << s;
|
||||||
|
s += 7;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
sleb128(char **p) {
|
||||||
|
long r = 0;
|
||||||
|
int s = 0;
|
||||||
|
for (;;) {
|
||||||
|
unsigned char b = *(unsigned char *)(*p)++;
|
||||||
|
if (b < 0x80) {
|
||||||
|
if (b & 0x40) {
|
||||||
|
r -= (0x80 - b) << s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r += (b & 0x3f) << s;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r += (b & 0x7f) << s;
|
||||||
|
s += 7;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
get_nth_dirname(int dir, char *p)
|
||||||
|
{
|
||||||
|
if (!dir--) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
while (dir) {
|
||||||
|
while (*p) p++;
|
||||||
|
p++;
|
||||||
|
if (!*p) {
|
||||||
|
fprintf(stderr, "Unexpected directory number %d in %s\n",
|
||||||
|
dir, binary_filename);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_filename(int file, char *include_directories, char *filenames,
|
||||||
|
line_info_t *line)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p = filenames;
|
||||||
|
char *filename;
|
||||||
|
unsigned long dir;
|
||||||
|
for (i = 1; i <= file; i++) {
|
||||||
|
filename = p;
|
||||||
|
if (!*p) {
|
||||||
|
/* Need to output binary file name? */
|
||||||
|
fprintf(stderr, "Unexpected file number %d in %s\n",
|
||||||
|
file, binary_filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (*p) p++;
|
||||||
|
p++;
|
||||||
|
dir = uleb128(&p);
|
||||||
|
/* last modified. */
|
||||||
|
uleb128(&p);
|
||||||
|
/* size of the file. */
|
||||||
|
uleb128(&p);
|
||||||
|
|
||||||
|
if (i == file) {
|
||||||
|
line->filename = filename;
|
||||||
|
line->dirname = get_nth_dirname(dir, include_directories);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_path_from_symbol(const char *symbol, const char **p, size_t *len)
|
||||||
|
{
|
||||||
|
if (symbol[0] == '0') {
|
||||||
|
/* libexecinfo */
|
||||||
|
*p = strchr(symbol, '/');
|
||||||
|
if (*p == NULL) return 0;
|
||||||
|
*len = strlen(*p);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* glibc */
|
||||||
|
const char *q;
|
||||||
|
*p = symbol;
|
||||||
|
q = strchr(symbol, '(');
|
||||||
|
if (q == NULL) return 0;
|
||||||
|
*len = q - symbol;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_line(int num_traces, void **traces,
|
||||||
|
unsigned long addr, int file, int line,
|
||||||
|
char *include_directories, char *filenames, line_info_t *lines)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < num_traces; i++) {
|
||||||
|
unsigned long a = (unsigned long)traces[i] - lines[i].base_addr;
|
||||||
|
/* 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, include_directories, filenames, &lines[i]);
|
||||||
|
lines[i].line = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_debug_line_cu(int num_traces, void **traces,
|
||||||
|
char **debug_line, line_info_t *lines)
|
||||||
|
{
|
||||||
|
char *p, *cu_end, *cu_start, *include_directories, *filenames;
|
||||||
|
unsigned long unit_length;
|
||||||
|
int default_is_stmt, line_base;
|
||||||
|
unsigned int header_length, minimum_instruction_length, line_range,
|
||||||
|
opcode_base;
|
||||||
|
unsigned char *standard_opcode_lengths;
|
||||||
|
|
||||||
|
/* The registers. */
|
||||||
|
unsigned long addr = 0;
|
||||||
|
unsigned int file = 1;
|
||||||
|
unsigned int line = 1;
|
||||||
|
unsigned int column = 0;
|
||||||
|
int is_stmt = default_is_stmt;
|
||||||
|
int basic_block = 0;
|
||||||
|
int end_sequence = 0;
|
||||||
|
int prologue_end = 0;
|
||||||
|
int epilogue_begin = 0;
|
||||||
|
unsigned int isa = 0;
|
||||||
|
|
||||||
|
p = *debug_line;
|
||||||
|
|
||||||
|
unit_length = *(unsigned int *)p;
|
||||||
|
p += sizeof(unsigned int);
|
||||||
|
if (unit_length == 0xffffffff) {
|
||||||
|
unit_length = *(unsigned long *)p;
|
||||||
|
p += sizeof(unsigned long);
|
||||||
|
}
|
||||||
|
|
||||||
|
cu_end = p + unit_length;
|
||||||
|
|
||||||
|
/*dwarf_version = *(unsigned short *)p;*/
|
||||||
|
p += 2;
|
||||||
|
|
||||||
|
header_length = *(unsigned int *)p;
|
||||||
|
p += sizeof(unsigned int);
|
||||||
|
|
||||||
|
cu_start = p + header_length;
|
||||||
|
|
||||||
|
minimum_instruction_length = *(unsigned char *)p;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
default_is_stmt = *(unsigned char *)p;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
line_base = *(char *)p;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
line_range = *(unsigned char *)p;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
opcode_base = *(unsigned char *)p;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
standard_opcode_lengths = (unsigned char *)p - 1;
|
||||||
|
p += opcode_base - 1;
|
||||||
|
|
||||||
|
include_directories = p;
|
||||||
|
|
||||||
|
/* skip include directories */
|
||||||
|
while (*p) {
|
||||||
|
while (*p) p++;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
p++;
|
||||||
|
|
||||||
|
filenames = p;
|
||||||
|
|
||||||
|
p = cu_start;
|
||||||
|
|
||||||
|
#define FILL_LINE() \
|
||||||
|
do { \
|
||||||
|
fill_line(num_traces, traces, addr, file, line, \
|
||||||
|
include_directories, filenames, lines); \
|
||||||
|
basic_block = prologue_end = epilogue_begin = 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
while (p < cu_end) {
|
||||||
|
unsigned long a;
|
||||||
|
unsigned char op = *p++;
|
||||||
|
switch (op) {
|
||||||
|
case DW_LNS_copy:
|
||||||
|
FILL_LINE();
|
||||||
|
break;
|
||||||
|
case DW_LNS_advance_pc:
|
||||||
|
a = uleb128(&p);
|
||||||
|
addr += a;
|
||||||
|
break;
|
||||||
|
case DW_LNS_advance_line: {
|
||||||
|
long a = sleb128(&p);
|
||||||
|
line += a;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_LNS_set_file:
|
||||||
|
file = uleb128(&p);
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_column:
|
||||||
|
column = uleb128(&p);
|
||||||
|
break;
|
||||||
|
case DW_LNS_negate_stmt:
|
||||||
|
is_stmt = !is_stmt;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_basic_block:
|
||||||
|
basic_block = 1;
|
||||||
|
break;
|
||||||
|
case DW_LNS_const_add_pc:
|
||||||
|
a = ((255 - opcode_base) / line_range) *
|
||||||
|
minimum_instruction_length;
|
||||||
|
addr += a;
|
||||||
|
break;
|
||||||
|
case DW_LNS_fixed_advance_pc:
|
||||||
|
a = *(unsigned char *)p++;
|
||||||
|
addr += a;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_prologue_end:
|
||||||
|
prologue_end = 1;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_epilogue_begin:
|
||||||
|
epilogue_begin = 1;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_isa:
|
||||||
|
isa = uleb128(&p);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
a = *(unsigned char *)p++;
|
||||||
|
op = *p++;
|
||||||
|
switch (op) {
|
||||||
|
case DW_LNE_end_sequence:
|
||||||
|
end_sequence = 1;
|
||||||
|
FILL_LINE();
|
||||||
|
addr = 0;
|
||||||
|
file = 1;
|
||||||
|
line = 1;
|
||||||
|
column = 0;
|
||||||
|
is_stmt = default_is_stmt;
|
||||||
|
end_sequence = 0;
|
||||||
|
isa = 0;
|
||||||
|
break;
|
||||||
|
case DW_LNE_set_address:
|
||||||
|
addr = *(unsigned long *)p;
|
||||||
|
p += sizeof(unsigned long);
|
||||||
|
break;
|
||||||
|
case DW_LNE_define_file:
|
||||||
|
fprintf(stderr, "Unsupported operation in %s\n",
|
||||||
|
binary_filename);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown extended opcode: %d in %s\n",
|
||||||
|
op, binary_filename);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
unsigned int addr_incr;
|
||||||
|
int line_incr;
|
||||||
|
a = op - opcode_base;
|
||||||
|
addr_incr = (a / line_range) * minimum_instruction_length;
|
||||||
|
line_incr = line_base + (a % line_range);
|
||||||
|
addr += addr_incr;
|
||||||
|
line += line_incr;
|
||||||
|
FILL_LINE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*debug_line = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_debug_line(int num_traces, void **traces,
|
||||||
|
char *debug_line, unsigned long size, line_info_t *lines)
|
||||||
|
{
|
||||||
|
char *debug_line_end = debug_line + size;
|
||||||
|
while (debug_line < debug_line_end) {
|
||||||
|
parse_debug_line_cu(num_traces, traces, &debug_line, lines);
|
||||||
|
}
|
||||||
|
if (debug_line != debug_line_end) {
|
||||||
|
fprintf(stderr, "Unexpected size of .debug_line in %s\n",
|
||||||
|
binary_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read file and fill lines */
|
||||||
|
static void
|
||||||
|
fill_lines(int num_traces, void **traces, char **syms,
|
||||||
|
char *file, line_info_t *lines)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *shstr;
|
||||||
|
char *section_name;
|
||||||
|
ElfW(Ehdr) *ehdr;
|
||||||
|
ElfW(Shdr) *shdr, *shstr_shdr, *debug_line_shdr = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < num_traces; i++) {
|
||||||
|
const char *path;
|
||||||
|
size_t len;
|
||||||
|
if (get_path_from_symbol(syms[i], &path, &len) &&
|
||||||
|
!strncmp(path, binary_filename, len)) {
|
||||||
|
lines[i].line = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ehdr = (ElfW(Ehdr) *)file;
|
||||||
|
shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
|
||||||
|
|
||||||
|
shstr_shdr = shdr + ehdr->e_shstrndx;
|
||||||
|
shstr = file + shstr_shdr->sh_offset;
|
||||||
|
|
||||||
|
for (i = 0; i < ehdr->e_shnum; i++) {
|
||||||
|
section_name = shstr + shdr[i].sh_name;
|
||||||
|
if (!strcmp(section_name, ".debug_line")) {
|
||||||
|
debug_line_shdr = shdr + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!debug_line_shdr) {
|
||||||
|
/* this file doesn't have .debug_line section */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_debug_line(num_traces, traces,
|
||||||
|
file + debug_line_shdr->sh_offset,
|
||||||
|
debug_line_shdr->sh_size,
|
||||||
|
lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DL_ITERATE_PHDR
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int num_traces;
|
||||||
|
char **syms;
|
||||||
|
line_info_t *lines;
|
||||||
|
} fill_base_addr_state_t;
|
||||||
|
|
||||||
|
static int
|
||||||
|
fill_base_addr(struct dl_phdr_info *info, size_t size, void *data)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;
|
||||||
|
for (i = 0; i < st->num_traces; i++) {
|
||||||
|
const char *path;
|
||||||
|
size_t len;
|
||||||
|
size_t name_len = strlen(info->dlpi_name);
|
||||||
|
|
||||||
|
if (get_path_from_symbol(st->syms[i], &path, &len) &&
|
||||||
|
(len == name_len || (len > name_len && path[len-name_len-1] == '/')) &&
|
||||||
|
!strncmp(path+len-name_len, info->dlpi_name, name_len)) {
|
||||||
|
st->lines[i].base_addr = info->dlpi_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_DL_ITERATE_PHDR */
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int fd;
|
||||||
|
/* async-signal unsafe */
|
||||||
|
line_info_t *lines = (line_info_t *)calloc(num_traces,
|
||||||
|
sizeof(line_info_t));
|
||||||
|
off_t filesize;
|
||||||
|
char *file;
|
||||||
|
|
||||||
|
/* Note that line info of shared objects might not be shown
|
||||||
|
if we don't have dl_iterate_phdr */
|
||||||
|
#ifdef HAVE_DL_ITERATE_PHDR
|
||||||
|
fill_base_addr_state_t fill_base_addr_state;
|
||||||
|
|
||||||
|
fill_base_addr_state.num_traces = num_traces;
|
||||||
|
fill_base_addr_state.syms = syms;
|
||||||
|
fill_base_addr_state.lines = lines;
|
||||||
|
/* maybe async-signal unsafe */
|
||||||
|
dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);
|
||||||
|
#endif /* HAVE_DL_ITERATE_PHDR */
|
||||||
|
|
||||||
|
for (i = 0; i < num_traces; i++) {
|
||||||
|
const char *path;
|
||||||
|
size_t len;
|
||||||
|
if (lines[i].line) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!get_path_from_symbol(syms[i], &path, &len)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(binary_filename, path, len);
|
||||||
|
binary_filename[len] = '\0';
|
||||||
|
|
||||||
|
fd = open(binary_filename, O_RDONLY);
|
||||||
|
filesize = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
/* async-signal unsafe */
|
||||||
|
file = (char *)mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
|
lines[i].fd = fd;
|
||||||
|
lines[i].mapped = file;
|
||||||
|
lines[i].mapped_size = filesize;
|
||||||
|
|
||||||
|
fill_lines(num_traces, trace, syms, file, lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fprintf may not be async-signal safe */
|
||||||
|
for (i = 0; i < num_traces; i++) {
|
||||||
|
line_info_t *line = &lines[i];
|
||||||
|
|
||||||
|
if (line->line > 0) {
|
||||||
|
fprintf(stderr, "%s ", syms[i]);
|
||||||
|
if (line->filename) {
|
||||||
|
if (line->dirname && line->dirname[0]) {
|
||||||
|
fprintf(stderr, "%s/", line->dirname);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s", line->filename);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "???");
|
||||||
|
}
|
||||||
|
fprintf(stderr, ":%d\n", line->line);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s\n", syms[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num_traces; i++) {
|
||||||
|
line_info_t *line = &lines[i];
|
||||||
|
if (line->fd) {
|
||||||
|
munmap(line->mapped, line->mapped_size);
|
||||||
|
close(line->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(__ELF__) */
|
|
@ -0,0 +1,21 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
addr2line.h -
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
|
||||||
|
Copyright (C) 2010 Shinichiro Hamaji
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef RUBY_ADDR2LINE_H
|
||||||
|
#define RUBY_ADDR2LINE_H
|
||||||
|
|
||||||
|
#ifdef __ELF__
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_dump_backtrace_with_lines(int num_traces, void **traces, char **syms);
|
||||||
|
|
||||||
|
#endif /* __ELF__ */
|
||||||
|
|
||||||
|
#endif /* RUBY_ADDR2LINE_H */
|
|
@ -91,6 +91,7 @@ COMMONOBJS = array.$(OBJEXT) \
|
||||||
vm_dump.$(OBJEXT) \
|
vm_dump.$(OBJEXT) \
|
||||||
thread.$(OBJEXT) \
|
thread.$(OBJEXT) \
|
||||||
cont.$(OBJEXT) \
|
cont.$(OBJEXT) \
|
||||||
|
addr2line.$(OBJEXT) \
|
||||||
$(BUILTIN_ENCOBJS) \
|
$(BUILTIN_ENCOBJS) \
|
||||||
$(BUILTIN_TRANSOBJS) \
|
$(BUILTIN_TRANSOBJS) \
|
||||||
$(MISSING)
|
$(MISSING)
|
||||||
|
|
|
@ -1300,7 +1300,7 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eacce
|
||||||
setsid telldir seekdir fchmod cosh sinh tanh log2 round\
|
setsid telldir seekdir fchmod cosh sinh tanh log2 round\
|
||||||
setuid setgid daemon select_large_fdset setenv unsetenv\
|
setuid setgid daemon select_large_fdset setenv unsetenv\
|
||||||
mktime timegm gmtime_r clock_gettime gettimeofday\
|
mktime timegm gmtime_r clock_gettime gettimeofday\
|
||||||
pread sendfile shutdown sigaltstack)
|
pread sendfile shutdown sigaltstack dl_iterate_phdr)
|
||||||
|
|
||||||
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
|
AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,
|
||||||
[AC_TRY_COMPILE([
|
[AC_TRY_COMPILE([
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "ruby/ruby.h"
|
#include "ruby/ruby.h"
|
||||||
|
#include "addr2line.h"
|
||||||
#include "vm_core.h"
|
#include "vm_core.h"
|
||||||
|
|
||||||
#define MAX_POSBUF 128
|
#define MAX_POSBUF 128
|
||||||
|
@ -788,9 +789,13 @@ rb_vm_bugreport(void)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (syms) {
|
if (syms) {
|
||||||
|
#ifdef __ELF__
|
||||||
|
rb_dump_backtrace_with_lines(n, trace, syms);
|
||||||
|
#else
|
||||||
for (i=0; i<n; i++) {
|
for (i=0; i<n; i++) {
|
||||||
fprintf(stderr, "%s\n", syms[i]);
|
fprintf(stderr, "%s\n", syms[i]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
free(syms);
|
free(syms);
|
||||||
}
|
}
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче