• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "partition_alloc/partition_alloc_base/debug/stack_trace.h"
6 
7 #include "partition_alloc/partition_alloc_base/logging.h"
8 #include "partition_alloc/partition_alloc_base/posix/eintr_wrapper.h"
9 #include "partition_alloc/partition_alloc_base/strings/safe_sprintf.h"
10 
11 #include <fcntl.h>
12 #include <string.h>
13 #include <unistd.h>
14 
15 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
16 #include <link.h>  // For ElfW() macro.
17 #endif
18 
19 #if BUILDFLAG(IS_APPLE)
20 #include <dlfcn.h>
21 #endif
22 
23 namespace partition_alloc::internal::base::debug {
24 
25 namespace {
26 
27 #if !BUILDFLAG(IS_APPLE)
28 
29 constexpr size_t kBufferSize = 4096u;
30 
31 enum {
32   kMapReadable = 1u,
33   kMapWritable = 2u,
34   kMapExecutable = 4u,
35   kMapPrivate = 8u,
36 };
37 
ParseAddress(const char ** ptr,const char * end,uintptr_t * address_return)38 bool ParseAddress(const char** ptr,
39                   const char* end,
40                   uintptr_t* address_return) {
41   const char* start = *ptr;
42 
43   // 0xNN = 2 characters
44   const char* max_address = start + sizeof(void*) * 2;
45   uintptr_t value = 0;
46 
47   const char* p = start;
48   for (; p < end && p < max_address; ++p) {
49     if ('0' <= *p && *p <= '9') {
50       value = (value << 4) | (unsigned char)(*p - '0');
51     } else if ('a' <= *p && *p <= 'f') {
52       value = (value << 4) | (unsigned char)(*p - 'a' + 10);
53     } else {
54       break;
55     }
56   }
57   if (p == start) {
58     return false;
59   }
60   *ptr = p;
61   if (address_return) {
62     *address_return = value;
63   }
64   return true;
65 }
66 
ParseInteger(const char ** ptr,const char * end)67 bool ParseInteger(const char** ptr, const char* end) {
68   const char* start = *ptr;
69 
70   const char* p = start;
71   for (; p < end && '0' <= *p && *p <= '9'; ++p)
72     ;
73   *ptr = p;
74   return p > start;
75 }
76 
ParsePermissions(const char ** ptr,const char * end,unsigned * permission_return)77 bool ParsePermissions(const char** ptr,
78                       const char* end,
79                       unsigned* permission_return) {
80   unsigned permission = 0u;
81   const char* p = *ptr;
82   if (p < end && (*p == 'r' || *p == '-')) {
83     permission |= (*p == 'r') ? kMapReadable : 0u;
84     ++p;
85   } else {
86     return false;
87   }
88   if (p < end && (*p == 'w' || *p == '-')) {
89     permission |= (*p == 'w') ? kMapWritable : 0u;
90     ++p;
91   } else {
92     return false;
93   }
94   if (p < end && (*p == 'x' || *p == '-')) {
95     permission |= (*p == 'w') ? kMapExecutable : 0u;
96     ++p;
97   } else {
98     return false;
99   }
100   if (p < end && (*p == 'p' || *p == '-' || *p == 's')) {
101     permission |= (*p == 'w') ? kMapPrivate : 0u;
102     ++p;
103   } else {
104     return false;
105   }
106   *ptr = p;
107   if (permission_return) {
108     *permission_return = permission;
109   }
110   return true;
111 }
112 
ParseMapsLine(const char * line_start,const char * line_end,uintptr_t * start_address_return,uintptr_t * end_address_return,unsigned * permission_return,uintptr_t * offset_return,const char ** module_name)113 bool ParseMapsLine(const char* line_start,
114                    const char* line_end,
115                    uintptr_t* start_address_return,
116                    uintptr_t* end_address_return,
117                    unsigned* permission_return,
118                    uintptr_t* offset_return,
119                    const char** module_name) {
120   const char* ptr = line_start;
121   if (!ParseAddress(&ptr, line_end, start_address_return)) {
122     return false;
123   }
124   // Delimiter
125   if (ptr >= line_end || *ptr != '-') {
126     return false;
127   }
128   ++ptr;
129   if (!ParseAddress(&ptr, line_end, end_address_return)) {
130     return false;
131   }
132 
133   // Delimiter
134   if (ptr >= line_end || *ptr != ' ') {
135     return false;
136   }
137   ++ptr;
138 
139   // skip permissions.
140   if (!ParsePermissions(&ptr, line_end, permission_return)) {
141     return false;
142   }
143 
144   // Delimiter
145   if (ptr >= line_end || *ptr != ' ') {
146     return false;
147   }
148   ++ptr;
149 
150   // skip offset
151   if (ParseAddress(&ptr, line_end, offset_return)) {
152     if (ptr >= line_end || *ptr != ' ') {
153       return false;
154     }
155     ++ptr;
156 
157     // skip dev
158     if (!ParseAddress(&ptr, line_end, nullptr)) {
159       return false;
160     }
161     if (ptr >= line_end || *ptr != ':') {
162       return false;
163     }
164     ++ptr;
165     if (!ParseAddress(&ptr, line_end, nullptr)) {
166       return false;
167     }
168 
169     // Delimiter
170     if (ptr >= line_end || *ptr != ' ') {
171       return false;
172     }
173     ++ptr;
174 
175     // skip inode
176     if (!ParseInteger(&ptr, line_end)) {
177       return false;
178     }
179   } else {
180     if (offset_return) {
181       *offset_return = 0u;
182     }
183   }
184   if (ptr >= line_end || *ptr != ' ') {
185     return false;
186   }
187   for (; ptr < line_end && *ptr == ' '; ++ptr)
188     ;
189   if (ptr <= line_end && module_name) {
190     *module_name = ptr;
191   }
192   return true;
193 }
194 
195 #if !BUILDFLAG(IS_ANDROID)
196 
ReadFromOffset(const int fd,void * buf,const size_t count,const size_t offset)197 ssize_t ReadFromOffset(const int fd,
198                        void* buf,
199                        const size_t count,
200                        const size_t offset) {
201   char* buf0 = reinterpret_cast<char*>(buf);
202   size_t num_bytes = 0;
203   while (num_bytes < count) {
204     ssize_t len;
205     len = PA_HANDLE_EINTR(pread(fd, buf0 + num_bytes, count - num_bytes,
206                                 static_cast<off_t>(offset + num_bytes)));
207     if (len < 0) {  // There was an error other than EINTR.
208       return -1;
209     }
210     if (len == 0) {  // Reached EOF.
211       break;
212     }
213     num_bytes += static_cast<size_t>(len);
214   }
215   return static_cast<ssize_t>(num_bytes);
216 }
217 
UpdateBaseAddress(unsigned permissions,uintptr_t start_address,uintptr_t * base_address)218 void UpdateBaseAddress(unsigned permissions,
219                        uintptr_t start_address,
220                        uintptr_t* base_address) {
221   // Determine the base address by reading ELF headers in process memory.
222   // Skip non-readable maps.
223   if (!(permissions & kMapReadable)) {
224     return;
225   }
226 
227   int mem_fd = PA_HANDLE_EINTR(open("/proc/self/mem", O_RDONLY));
228   if (mem_fd == -1) {
229     PA_RAW_LOG(ERROR, "Failed to open /proc/self/mem\n");
230     return;
231   }
232 
233   ElfW(Ehdr) ehdr;
234   ssize_t len =
235       ReadFromOffset(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address);
236   if (len == sizeof(ElfW(Ehdr))) {
237     if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
238       switch (ehdr.e_type) {
239         case ET_EXEC:
240           *base_address = 0;
241           break;
242         case ET_DYN:
243           // Find the segment containing file offset 0. This will correspond
244           // to the ELF header that we just read. Normally this will have
245           // virtual address 0, but this is not guaranteed. We must subtract
246           // the virtual address from the address where the ELF header was
247           // mapped to get the base address.
248           //
249           // If we fail to find a segment for file offset 0, use the address
250           // of the ELF header as the base address.
251           *base_address = start_address;
252           for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
253             ElfW(Phdr) phdr;
254             len =
255                 ReadFromOffset(mem_fd, &phdr, sizeof(ElfW(Phdr)),
256                                start_address + ehdr.e_phoff + i * sizeof(phdr));
257             if (len == sizeof(ElfW(Phdr)) && phdr.p_type == PT_LOAD &&
258                 phdr.p_offset == 0) {
259               *base_address = start_address - phdr.p_vaddr;
260               break;
261             }
262           }
263           break;
264         default:
265           // ET_REL or ET_CORE. These aren't directly executable, so they don't
266           // affect the base address.
267           break;
268       }
269     }
270   }
271   close(mem_fd);
272 }
273 
274 #endif  // !BUILDFLAG(IS_ANDROID)
275 
PrintStackTraceInternal(const void ** trace,size_t count)276 void PrintStackTraceInternal(const void** trace, size_t count) {
277   int fd = PA_HANDLE_EINTR(open("/proc/self/maps", O_RDONLY));
278   if (fd == -1) {
279     PA_RAW_LOG(ERROR, "Failed to open /proc/self/maps\n");
280     return;
281   }
282 
283   char buffer[kBufferSize];
284   char* dest = buffer;
285   char* buffer_end = buffer + kBufferSize;
286 #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
287   uintptr_t base_address = 0u;
288 #endif
289 
290   while (dest < buffer_end) {
291     ssize_t bytes_read = PA_HANDLE_EINTR(read(fd, dest, buffer_end - dest));
292     if (bytes_read == 0) {
293       break;
294     }
295     if (bytes_read < 0) {
296       PA_RAW_LOG(ERROR, "Failed to read /proc/self/maps\n");
297       break;
298     }
299 
300     char* read_end = dest + bytes_read;
301     char* parsed = buffer;
302     char* line_start = buffer;
303     // It is difficult to remember entire memory regions and to use them
304     // to process stack traces. Instead, try to parse each line of
305     // /proc/self/maps and to process matched stack traces. This will
306     // make the order of the output stack traces different from the input.
307     for (char* line_end = buffer; line_end < read_end; ++line_end) {
308       if (*line_end == '\n') {
309         parsed = line_end + 1;
310         *line_end = '\0';
311         uintptr_t start_address = 0u;
312         uintptr_t end_address = 0u;
313         uintptr_t offset = 0u;
314         unsigned permissions = 0u;
315         const char* module_name = nullptr;
316         bool ok =
317             ParseMapsLine(line_start, line_end, &start_address, &end_address,
318                           &permissions, &offset, &module_name);
319         if (ok) {
320 #if !BUILDFLAG(IS_ANDROID)
321           UpdateBaseAddress(permissions, start_address, &base_address);
322 #endif
323           if (module_name && *module_name != '\0') {
324             for (size_t i = 0; i < count; i++) {
325 #if BUILDFLAG(IS_ANDROID)
326               // Subtract one as return address of function may be in the next
327               // function when a function is annotated as noreturn.
328               uintptr_t address = reinterpret_cast<uintptr_t>(trace[i]) - 1;
329               uintptr_t base_address = start_address;
330 #else
331               uintptr_t address = reinterpret_cast<uintptr_t>(trace[i]);
332 #endif
333               if (start_address <= address && address < end_address) {
334                 OutputStackTrace(i, address, base_address, module_name, offset);
335               }
336             }
337           }
338         } else {
339           PA_RAW_LOG(ERROR, "Parse failed.\n");
340         }
341         line_start = parsed;
342       }
343     }
344     if (parsed == buffer) {
345       // /proc/self/maps contains too long line (> kBufferSize).
346       PA_RAW_LOG(ERROR, "/proc/self/maps has too long line.\n");
347       break;
348     }
349     if (parsed < read_end) {
350       size_t left_chars = read_end - parsed;
351       memmove(buffer, parsed, left_chars);
352       dest = buffer + left_chars;
353     } else {
354       dest = buffer;
355     }
356   }
357   close(fd);
358 }
359 #endif  // !BUILDFLAG(IS_APPLE)
360 
361 #if BUILDFLAG(IS_APPLE)
362 // Since /proc/self/maps is not available, use dladdr() to obtain module
363 // names and offsets inside the modules from the given addresses.
PrintStackTraceInternal(const void * const * trace,size_t size)364 void PrintStackTraceInternal(const void* const* trace, size_t size) {
365   // NOTE: This code MUST be async-signal safe (it's used by in-process
366   // stack dumping signal handler). NO malloc or stdio is allowed here.
367 
368   Dl_info dl_info;
369   for (size_t i = 0; i < size; ++i) {
370     const bool dl_info_found = dladdr(trace[i], &dl_info) != 0;
371     if (dl_info_found) {
372       const char* last_sep = strrchr(dl_info.dli_fname, '/');
373       const char* basename = last_sep ? last_sep + 1 : dl_info.dli_fname;
374 
375       // Use atos with --offset to obtain symbols from the printed addresses,
376       // e.g.
377       //  #01 0x0000000106225d6c  (base_unittests+0x0000000001999d6c)
378       //  bash-3.2$ atos -o out/default/base_unittests --offset
379       //   0x0000000001999d6c
380       //  partition_alloc::internal::PartitionAllocTest_Basic_Test::TestBody()
381       //  (in base_unittests) + 156
382       OutputStackTrace(i, reinterpret_cast<uintptr_t>(trace[i]),
383                        reinterpret_cast<uintptr_t>(dl_info.dli_fbase), basename,
384                        0u);
385     } else {
386       OutputStackTrace(i, reinterpret_cast<uintptr_t>(trace[i]), 0u, "???", 0u);
387     }
388   }
389 }
390 #endif  // BUILDFLAG(IS_APPLE)
391 
392 }  // namespace
393 
PrintStackTrace(const void ** trace,size_t count)394 void PrintStackTrace(const void** trace, size_t count) {
395   PrintStackTraceInternal(trace, count);
396 }
397 
398 // stack_trace_android.cc defines its own OutputStackTrace.
399 #if !BUILDFLAG(IS_ANDROID)
OutputStackTrace(unsigned index,uintptr_t address,uintptr_t base_address,const char * module_name,uintptr_t)400 void OutputStackTrace(unsigned index,
401                       uintptr_t address,
402                       uintptr_t base_address,
403                       const char* module_name,
404                       uintptr_t) {
405   char buffer[256];
406   strings::SafeSPrintf(buffer, "#%02d 0x%0x  (%s+0x%0x)\n", index, address,
407                        module_name, address - base_address);
408   PA_RAW_LOG(INFO, buffer);
409 }
410 #endif  // !BUILDFLAG(IS_ANDROID)
411 
412 }  // namespace partition_alloc::internal::base::debug
413