From: Shinichiro Hamaji Date: 2010-11-29T10:38:36+09:00 Subject: [ruby-dev:42655] [Ruby 1.9-Feature#4096][Open] Follow .gnu_debuglink section. Feature #4096: Follow .gnu_debuglink section. http://redmine.ruby-lang.org/issues/show/4096 起票者: Shinichiro Hamaji ステータス: Open, 優先度: Normal 浜地です。 先日取り込んでいただいた行情報のパッチですが、 ディストリビューションなんかが配布する ruby バイナリは、 # debug 情報を持っていない /usr/bin/ruby # debug 情報を持っている # debug package をインストールした場合に存在する。 /usr/lib/debug/usr/bin/ruby とかいう感じで二つに別れています。 バグレポートする人の中には debug package を入れている人も いるかもしれませんし、これに対応するのは一定の価値があるかもなぁ ということで書いたパッチです。 Subject: [PATCH] Follow .gnu_debuglink section. With this patch, a user of distribution provided ruby will see line info if s/he has a debug package for ruby. --- addr2line.c | 97 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 70 insertions(+), 27 deletions(-) diff --git a/addr2line.c b/addr2line.c index 443333f..97bd652 100644 --- a/addr2line.c +++ b/addr2line.c @@ -382,14 +382,71 @@ parse_debug_line(int num_traces, void **traces, /* read file and fill lines */ static void -fill_lines(int num_traces, void **traces, char **syms, - char *file, line_info_t *lines) +fill_lines(int num_traces, void **traces, char **syms, int check_debuglink, + line_info_t *current_line, line_info_t *lines); + +static void +follow_debuglink(char *debuglink, int num_traces, void **traces, char **syms, + line_info_t *current_line, line_info_t *lines) +{ + /* Ideally we should check 4 paths to follow gnu_debuglink, + but we handle only one case for now as this format is used + by some linux distributions. See GDB's info for detail. */ + static const char global_debug_dir[] = "/usr/lib/debug"; + char *p, *subdir; + + p = strrchr(binary_filename, '/'); + if (!p) { + return; + } + p[1] = '\0'; + + subdir = (char *)alloca(strlen(binary_filename) + 1); + strcpy(subdir, binary_filename); + strcpy(binary_filename, global_debug_dir); + strncat(binary_filename, subdir, + PATH_MAX - strlen(binary_filename) - 1); + strncat(binary_filename, debuglink, + PATH_MAX - strlen(binary_filename) - 1); + + munmap(current_line->mapped, current_line->mapped_size); + close(current_line->fd); + fill_lines(num_traces, traces, syms, 0, current_line, lines); +} + +/* read file and fill lines */ +static void +fill_lines(int num_traces, void **traces, char **syms, int check_debuglink, + line_info_t *current_line, line_info_t *lines) { int i; char *shstr; char *section_name; ElfW(Ehdr) *ehdr; - ElfW(Shdr) *shdr, *shstr_shdr, *debug_line_shdr = NULL; + ElfW(Shdr) *shdr, *shstr_shdr; + ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL; + int fd; + off_t filesize; + char *file; + + fd = open(binary_filename, O_RDONLY); + if (fd < 0) { + return; + } + 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); + if (file == MAP_FAILED) { + int e = errno; + close(fd); + fprintf(stderr, "mmap: %s\n", strerror(e)); + return; + } + + current_line->fd = fd; + current_line->mapped = file; + current_line->mapped_size = filesize; for (i = 0; i < num_traces; i++) { const char *path; @@ -411,11 +468,19 @@ fill_lines(int num_traces, void **traces, char **syms, if (!strcmp(section_name, ".debug_line")) { debug_line_shdr = shdr + i; break; + } else if (!strcmp(section_name, ".gnu_debuglink")) { + gnu_debuglink_shdr = shdr + i; } } if (!debug_line_shdr) { - /* this file doesn't have .debug_line section */ + /* This file doesn't have .debug_line section, + let's check .gnu_debuglink section instead. */ + if (gnu_debuglink_shdr && check_debuglink) { + follow_debuglink(file + gnu_debuglink_shdr->sh_offset, + num_traces, traces, syms, + current_line, lines); + } return; } @@ -458,12 +523,9 @@ 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 */ @@ -491,26 +553,7 @@ rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms) strncpy(binary_filename, path, len); binary_filename[len] = '\0'; - fd = open(binary_filename, O_RDONLY); - if (fd < 0) { - continue; - } - 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); - if (file == MAP_FAILED) { - int e = errno; - close(fd); - fprintf(stderr, "mmap: %s\n", strerror(e)); - continue; - } - - lines[i].fd = fd; - lines[i].mapped = file; - lines[i].mapped_size = filesize; - - fill_lines(num_traces, trace, syms, file, lines); + fill_lines(num_traces, trace, syms, 1, &lines[i], lines); } /* fprintf may not be async-signal safe */ -- 1.7.2.3 ---------------------------------------- http://redmine.ruby-lang.org