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