• 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/process/process_handle.h"
9 #include "partition_alloc/partition_alloc_base/strings/safe_sprintf.h"
10 
11 #include <windows.h>
12 #include <algorithm>
13 
14 #include <psapi.h>  // Depends on "windows.h"
15 
16 namespace partition_alloc::internal::base::debug {
17 
18 namespace {
19 
PrintStackTraceInternal(const void ** trace,size_t count)20 void PrintStackTraceInternal(const void** trace, size_t count) {
21   HANDLE process_handle = OpenProcess(
22       PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcId());
23   if (!process_handle) {
24     return;
25   }
26 
27   constexpr size_t kMaxTraces = 32u;
28   count = std::max(count, kMaxTraces);
29   bool is_output_trace[kMaxTraces];
30   for (size_t i = 0; i < count; ++i) {
31     is_output_trace[i] = false;
32   }
33   DWORD bytes_required = 0;
34   if (EnumProcessModules(process_handle, nullptr, 0, &bytes_required)) {
35     HMODULE* module_array = nullptr;
36     LPBYTE module_array_bytes = nullptr;
37 
38     if (bytes_required) {
39       module_array_bytes = (LPBYTE)LocalAlloc(LPTR, bytes_required);
40       if (module_array_bytes) {
41         unsigned int module_count = bytes_required / sizeof(HMODULE);
42         module_array = reinterpret_cast<HMODULE*>(module_array_bytes);
43 
44         if (EnumProcessModules(process_handle, module_array, bytes_required,
45                                &bytes_required)) {
46           for (unsigned i = 0; i < module_count; ++i) {
47             MODULEINFO info;
48             if (GetModuleInformation(process_handle, module_array[i], &info,
49                                      sizeof(info))) {
50               char module_name[MAX_PATH + 1];
51               bool module_name_checked = false;
52               for (unsigned j = 0; j < count; j++) {
53                 uintptr_t base_of_dll =
54                     reinterpret_cast<uintptr_t>(info.lpBaseOfDll);
55                 uintptr_t address = reinterpret_cast<uintptr_t>(trace[j]);
56                 if (base_of_dll <= address &&
57                     address < base_of_dll + info.SizeOfImage) {
58                   if (!module_name_checked) {
59                     size_t module_name_length = GetModuleFileNameExA(
60                         process_handle, module_array[i], module_name,
61                         sizeof(module_name) - 1);
62                     module_name[module_name_length] = '\0';
63                     module_name_checked = true;
64                   }
65                   // llvm-symbolizer needs --relative-address to symbolize the
66                   // "address - base_of_dll".
67                   char buffer[256];
68                   strings::SafeSPrintf(buffer, "#%d 0x%x (%s+0x%x)\n", j,
69                                        address, module_name,
70                                        address - base_of_dll);
71                   PA_RAW_LOG(INFO, buffer);
72                   is_output_trace[j] = true;
73                 }
74               }
75             }
76           }
77         }
78         LocalFree(module_array_bytes);
79       }
80     }
81   }
82 
83   for (size_t i = 0; i < count; ++i) {
84     if (is_output_trace[i]) {
85       continue;
86     }
87     char buffer[256];
88     strings::SafeSPrintf(buffer, "#%d 0x%x <unknown>\n", i,
89                          reinterpret_cast<uintptr_t>(trace[i]));
90     PA_RAW_LOG(INFO, buffer);
91   }
92 
93   CloseHandle(process_handle);
94 }
95 
96 }  // namespace
97 
CollectStackTrace(const void ** trace,size_t count)98 PA_NOINLINE size_t CollectStackTrace(const void** trace, size_t count) {
99   // When walking our own stack, use CaptureStackBackTrace().
100   return CaptureStackBackTrace(0, count, const_cast<void**>(trace), NULL);
101 }
102 
PrintStackTrace(const void ** trace,size_t count)103 void PrintStackTrace(const void** trace, size_t count) {
104   PrintStackTraceInternal(trace, count);
105 }
106 
107 }  // namespace partition_alloc::internal::base::debug
108