blob: 624b1c6ff3f71031e71b920566cbbe3e0041162a [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "partition_alloc/partition_alloc_base/debug/stack_trace.h"
#include "partition_alloc/partition_alloc_base/logging.h"
#include "partition_alloc/partition_alloc_base/process/process_handle.h"
#include "partition_alloc/partition_alloc_base/strings/safe_sprintf.h"
#include <windows.h>
#include <algorithm>
#include <psapi.h> // Depends on "windows.h"
namespace partition_alloc::internal::base::debug {
namespace {
void PrintStackTraceInternal(const void** trace, size_t count) {
HANDLE process_handle = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcId());
if (!process_handle) {
return;
}
constexpr size_t kMaxTraces = 32u;
count = std::max(count, kMaxTraces);
bool is_output_trace[kMaxTraces];
for (size_t i = 0; i < count; ++i) {
is_output_trace[i] = false;
}
DWORD bytes_required = 0;
if (EnumProcessModules(process_handle, nullptr, 0, &bytes_required)) {
HMODULE* module_array = nullptr;
LPBYTE module_array_bytes = nullptr;
if (bytes_required) {
module_array_bytes = (LPBYTE)LocalAlloc(LPTR, bytes_required);
if (module_array_bytes) {
unsigned int module_count = bytes_required / sizeof(HMODULE);
module_array = reinterpret_cast<HMODULE*>(module_array_bytes);
if (EnumProcessModules(process_handle, module_array, bytes_required,
&bytes_required)) {
for (unsigned i = 0; i < module_count; ++i) {
MODULEINFO info;
if (GetModuleInformation(process_handle, module_array[i], &info,
sizeof(info))) {
char module_name[MAX_PATH + 1];
bool module_name_checked = false;
for (unsigned j = 0; j < count; j++) {
uintptr_t base_of_dll =
reinterpret_cast<uintptr_t>(info.lpBaseOfDll);
uintptr_t address = reinterpret_cast<uintptr_t>(trace[j]);
if (base_of_dll <= address &&
address < base_of_dll + info.SizeOfImage) {
if (!module_name_checked) {
size_t module_name_length = GetModuleFileNameExA(
process_handle, module_array[i], module_name,
sizeof(module_name) - 1);
module_name[module_name_length] = '\0';
module_name_checked = true;
}
// llvm-symbolizer needs --relative-address to symbolize the
// "address - base_of_dll".
char buffer[256];
strings::SafeSPrintf(buffer, "#%d 0x%x (%s+0x%x)\n", j,
address, module_name,
address - base_of_dll);
PA_RAW_LOG(INFO, buffer);
is_output_trace[j] = true;
}
}
}
}
}
LocalFree(module_array_bytes);
}
}
}
for (size_t i = 0; i < count; ++i) {
if (is_output_trace[i]) {
continue;
}
char buffer[256];
strings::SafeSPrintf(buffer, "#%d 0x%x <unknown>\n", i,
reinterpret_cast<uintptr_t>(trace[i]));
PA_RAW_LOG(INFO, buffer);
}
CloseHandle(process_handle);
}
} // namespace
PA_NOINLINE size_t CollectStackTrace(const void** trace, size_t count) {
// When walking our own stack, use CaptureStackBackTrace().
return CaptureStackBackTrace(0, count, const_cast<void**>(trace), NULL);
}
void PrintStackTrace(const void** trace, size_t count) {
PrintStackTraceInternal(trace, count);
}
} // namespace partition_alloc::internal::base::debug