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