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