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