1 //===-- tsan_symbolize_addr2line.cc ---------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
11 #include "sanitizer_common/sanitizer_common.h"
12 #include "sanitizer_common/sanitizer_libc.h"
13 #include "tsan_symbolize.h"
14 #include "tsan_mman.h"
16 #include "tsan_platform.h"
23 #include <linux/limits.h>
24 #include <sys/types.h>
43 struct DlIteratePhdrCtx
{
44 SectionDesc
*sections
;
48 static void NOINLINE
InitModule(ModuleDesc
*m
) {
50 if (pipe(&outfd
[0])) {
51 Printf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno
);
56 Printf("ThreadSanitizer: infd pipe() failed (%d)\n", errno
);
61 internal_close(STDOUT_FILENO
);
62 internal_close(STDIN_FILENO
);
63 internal_dup2(outfd
[0], STDIN_FILENO
);
64 internal_dup2(infd
[1], STDOUT_FILENO
);
65 internal_close(outfd
[0]);
66 internal_close(outfd
[1]);
67 internal_close(infd
[0]);
68 internal_close(infd
[1]);
69 for (int fd
= getdtablesize(); fd
> 2; fd
--)
71 execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m
->fullname
, 0);
74 Printf("ThreadSanitizer: failed to fork symbolizer\n");
77 internal_close(outfd
[0]);
78 internal_close(infd
[1]);
83 static int dl_iterate_phdr_cb(dl_phdr_info
*info
, size_t size
, void *arg
) {
84 DlIteratePhdrCtx
*ctx
= (DlIteratePhdrCtx
*)arg
;
85 InternalScopedBuffer
<char> tmp(128);
87 internal_snprintf(tmp
.data(), tmp
.size(), "/proc/%d/exe",
88 (int)internal_getpid());
89 info
->dlpi_name
= tmp
.data();
91 ctx
->is_first
= false;
92 if (info
->dlpi_name
== 0 || info
->dlpi_name
[0] == 0)
94 ModuleDesc
*m
= (ModuleDesc
*)internal_alloc(MBlockReportStack
,
96 m
->fullname
= internal_strdup(info
->dlpi_name
);
97 m
->name
= internal_strrchr(m
->fullname
, '/');
101 m
->name
= m
->fullname
;
102 m
->base
= (uptr
)info
->dlpi_addr
;
105 DPrintf2("Module %s %zx\n", m
->name
, m
->base
);
106 for (int i
= 0; i
< info
->dlpi_phnum
; i
++) {
107 const Elf64_Phdr
*s
= &info
->dlpi_phdr
[i
];
108 DPrintf2(" Section p_type=%zx p_offset=%zx p_vaddr=%zx p_paddr=%zx"
109 " p_filesz=%zx p_memsz=%zx p_flags=%zx p_align=%zx\n",
110 (uptr
)s
->p_type
, (uptr
)s
->p_offset
, (uptr
)s
->p_vaddr
,
111 (uptr
)s
->p_paddr
, (uptr
)s
->p_filesz
, (uptr
)s
->p_memsz
,
112 (uptr
)s
->p_flags
, (uptr
)s
->p_align
);
113 if (s
->p_type
!= PT_LOAD
)
115 SectionDesc
*sec
= (SectionDesc
*)internal_alloc(MBlockReportStack
,
116 sizeof(SectionDesc
));
118 sec
->base
= info
->dlpi_addr
+ s
->p_vaddr
;
119 sec
->end
= sec
->base
+ s
->p_memsz
;
120 sec
->next
= ctx
->sections
;
122 DPrintf2(" Section %zx-%zx\n", sec
->base
, sec
->end
);
127 static SectionDesc
*InitSections() {
128 DlIteratePhdrCtx ctx
= {0, true};
129 dl_iterate_phdr(dl_iterate_phdr_cb
, &ctx
);
133 static SectionDesc
*GetSectionDesc(uptr addr
) {
134 static SectionDesc
*sections
= 0;
136 sections
= InitSections();
137 for (SectionDesc
*s
= sections
; s
; s
= s
->next
) {
138 if (addr
>= s
->base
&& addr
< s
->end
) {
139 if (s
->module
->inp_fd
== -1)
140 InitModule(s
->module
);
147 ReportStack
*SymbolizeCodeAddr2Line(uptr addr
) {
148 SectionDesc
*s
= GetSectionDesc(addr
);
150 return NewReportStackEntry(addr
);
151 ModuleDesc
*m
= s
->module
;
152 uptr offset
= addr
- m
->base
;
154 internal_snprintf(addrstr
, sizeof(addrstr
), "%p\n", (void*)offset
);
155 if (0 >= internal_write(m
->out_fd
, addrstr
, internal_strlen(addrstr
))) {
156 Printf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
160 InternalScopedBuffer
<char> func(1024);
161 ssize_t len
= internal_read(m
->inp_fd
, func
.data(), func
.size() - 1);
163 Printf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
167 func
.data()[len
] = 0;
168 ReportStack
*res
= NewReportStackEntry(addr
);
169 res
->module
= internal_strdup(m
->name
);
170 res
->offset
= offset
;
171 char *pos
= (char*)internal_strchr(func
.data(), '\n');
172 if (pos
&& func
[0] != '?') {
173 res
->func
= (char*)internal_alloc(MBlockReportStack
, pos
- func
.data() + 1);
174 internal_memcpy(res
->func
, func
.data(), pos
- func
.data());
175 res
->func
[pos
- func
.data()] = 0;
176 char *pos2
= (char*)internal_strchr(pos
, ':');
178 res
->file
= (char*)internal_alloc(MBlockReportStack
, pos2
- pos
- 1 + 1);
179 internal_memcpy(res
->file
, pos
+ 1, pos2
- pos
- 1);
180 res
->file
[pos2
- pos
- 1] = 0;
181 res
->line
= atoi(pos2
+ 1);
187 ReportStack
*SymbolizeDataAddr2Line(uptr addr
) {
191 } // namespace __tsan