Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c86860f5e2 | ||
![]() |
ef04c53283 | ||
![]() |
897c1bb4d6 | ||
![]() |
7ac616335d | ||
![]() |
5b47d9d474 | ||
![]() |
622588226d | ||
![]() |
be470f3a11 | ||
![]() |
eb81077a4f | ||
![]() |
8ba5453573 | ||
![]() |
b0fbff302a | ||
![]() |
43b75f42a7 | ||
![]() |
8ca937a3a7 |
@@ -178,12 +178,8 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
|
||||
out->flt_save.data_offset = fpregs.rdp;
|
||||
out->flt_save.data_selector = 0; // We don't have this.
|
||||
out->flt_save.mx_csr = fpregs.mxcsr;
|
||||
#if defined (__ANDROID__)
|
||||
// Internal bug b/18097559
|
||||
out->flt_save.mx_csr_mask = fpregs.mxcsr_mask;
|
||||
#else
|
||||
out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
|
||||
#endif
|
||||
|
||||
my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
|
||||
my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
|
||||
}
|
||||
|
@@ -188,6 +188,24 @@ void RestoreAlternateStackLocked() {
|
||||
stack_installed = false;
|
||||
}
|
||||
|
||||
void InstallDefaultHandler(int sig) {
|
||||
#if defined(__ANDROID__)
|
||||
// Android L+ expose signal and sigaction symbols that override the system
|
||||
// ones. There is a bug in these functions where a request to set the handler
|
||||
// to SIG_DFL is ignored. In that case, an infinite loop is entered as the
|
||||
// signal is repeatedly sent to breakpad's signal handler.
|
||||
// To work around this, directly call the system's sigaction.
|
||||
struct kernel_sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sys_sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler_ = SIG_DFL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t));
|
||||
#else
|
||||
signal(sig, SIG_DFL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The global exception handler stack. This is needed because there may exist
|
||||
// multiple ExceptionHandler instances in a process. Each will have itself
|
||||
// registered in this stack.
|
||||
@@ -283,7 +301,7 @@ void ExceptionHandler::RestoreHandlersLocked() {
|
||||
|
||||
for (int i = 0; i < kNumHandledSignals; ++i) {
|
||||
if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
|
||||
signal(kExceptionSignals[i], SIG_DFL);
|
||||
InstallDefaultHandler(kExceptionSignals[i]);
|
||||
}
|
||||
}
|
||||
handlers_installed = false;
|
||||
@@ -323,7 +341,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
if (sigaction(sig, &cur_handler, NULL) == -1) {
|
||||
// When resetting the handler fails, try to reset the
|
||||
// default one to avoid an infinite loop here.
|
||||
signal(sig, SIG_DFL);
|
||||
InstallDefaultHandler(sig);
|
||||
}
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
return;
|
||||
@@ -340,14 +358,15 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
|
||||
// previously installed handler. Then, when the signal is retriggered, it will
|
||||
// be delivered to the appropriate handler.
|
||||
if (handled) {
|
||||
signal(sig, SIG_DFL);
|
||||
InstallDefaultHandler(sig);
|
||||
} else {
|
||||
RestoreHandlersLocked();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_handler_stack_mutex_);
|
||||
|
||||
if (info->si_pid || sig == SIGABRT) {
|
||||
// info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
|
||||
if (info->si_code <= 0 || sig == SIGABRT) {
|
||||
// This signal was triggered by somebody sending us the signal with kill().
|
||||
// In order to retrigger it, we have to queue a new signal by calling
|
||||
// kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
|
||||
|
@@ -41,7 +41,6 @@
|
||||
#include "client/linux/log/log.h"
|
||||
#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -51,7 +50,6 @@ using google_breakpad::LinuxPtraceDumper;
|
||||
using google_breakpad::MappingInfo;
|
||||
using google_breakpad::MappingList;
|
||||
using google_breakpad::RawContextCPU;
|
||||
using google_breakpad::scoped_array;
|
||||
using google_breakpad::SeccompUnwinder;
|
||||
using google_breakpad::ThreadInfo;
|
||||
using google_breakpad::UContextReader;
|
||||
@@ -69,14 +67,20 @@ class MicrodumpWriter {
|
||||
#endif
|
||||
dumper_(dumper),
|
||||
mapping_list_(mappings),
|
||||
log_line_(new char[kLineBufferSize]) {
|
||||
log_line_.get()[0] = '\0'; // Clear out the log line buffer.
|
||||
log_line_(NULL) {
|
||||
log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
|
||||
if (log_line_)
|
||||
log_line_[0] = '\0'; // Clear out the log line buffer.
|
||||
}
|
||||
|
||||
~MicrodumpWriter() { dumper_->ThreadsResume(); }
|
||||
|
||||
bool Init() {
|
||||
if (!dumper_->Init())
|
||||
// In the exceptional case where the system was out of memory and there
|
||||
// wasn't even room to allocate the line buffer, bail out. There is nothing
|
||||
// useful we can possibly achieve without the ability to Log. At least let's
|
||||
// try to not crash.
|
||||
if (!dumper_->Init() || !log_line_)
|
||||
return false;
|
||||
return dumper_->ThreadsSuspend();
|
||||
}
|
||||
@@ -105,7 +109,7 @@ class MicrodumpWriter {
|
||||
|
||||
// Stages the given string in the current line buffer.
|
||||
void LogAppend(const char* str) {
|
||||
my_strlcat(log_line_.get(), str, kLineBufferSize);
|
||||
my_strlcat(log_line_, str, kLineBufferSize);
|
||||
}
|
||||
|
||||
// As above (required to take precedence over template specialization below).
|
||||
@@ -135,8 +139,8 @@ class MicrodumpWriter {
|
||||
|
||||
// Writes out the current line buffer on the system log.
|
||||
void LogCommitLine() {
|
||||
LogLine(log_line_.get());
|
||||
my_strlcpy(log_line_.get(), "", kLineBufferSize);
|
||||
LogLine(log_line_);
|
||||
my_strlcpy(log_line_, "", kLineBufferSize);
|
||||
}
|
||||
|
||||
bool DumpOSInformation() {
|
||||
@@ -363,7 +367,7 @@ class MicrodumpWriter {
|
||||
#endif
|
||||
LinuxDumper* dumper_;
|
||||
const MappingList& mapping_list_;
|
||||
scoped_array<char> log_line_;
|
||||
char* log_line_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@@ -34,9 +34,11 @@
|
||||
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
|
||||
// The following quirks are currently handled by this file:
|
||||
// - MIPS: Keep using forked definitions of user.h structs. The definition in
|
||||
// the NDK is completely different.
|
||||
// Internal bug b/18097715
|
||||
// the NDK is completely different. Internal bug b/18097715
|
||||
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
|
||||
// - x86_64: Override a typo in user_fpregs_struct (mxcsr_mask -> mxcr_mask).
|
||||
// The typo has been fixed in NDK r10d, but a preprocessor workaround is
|
||||
// required to make breakpad build with r10c and lower (more details below).
|
||||
// - Other platforms: Just use the Android NDK unchanged.
|
||||
|
||||
#ifdef __mips__
|
||||
@@ -113,8 +115,24 @@ struct user_fpregs_struct {
|
||||
|
||||
#else // __mips__
|
||||
|
||||
// TODO(primiano): remove this after Chromium has stably rolled to NDK r10d.
|
||||
// Historical context: NDK releases < r10d had a typo in sys/user.h (mxcsr_mask
|
||||
// instead of mxcr_mask), which is fixed in r10d. However, just switching to use
|
||||
// the correct one (mxcr_mask) would put Breakpad in a state where it can be
|
||||
// rolled in chromium only atomically with the r10d NDK. A revert of either
|
||||
// project (android_tools, breakpad) would make the other one unrollable.
|
||||
// This hack makes breakpad code compatible with both r10c and r10d NDKs,
|
||||
// reducing the dependency entangling with android_tools.
|
||||
#if defined(__x86_64__)
|
||||
#define mxcsr_mask mxcr_mask
|
||||
#endif
|
||||
|
||||
#include_next <sys/user.h>
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#undef mxcsr_mask
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@@ -1,23 +1,39 @@
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Disclaimer
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
@@ -1,23 +1,39 @@
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Disclaimer
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_CONVERT_UTF_H_
|
||||
|
@@ -37,16 +37,34 @@
|
||||
'all_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
'$(VSInstallDir)\DIA SDK\include',
|
||||
'$(VSInstallDir)/DIA SDK/include',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalDependencies': [
|
||||
'$(VSInstallDir)\DIA SDK\lib\diaguids.lib',
|
||||
'diaguids.lib',
|
||||
'imagehlp.lib',
|
||||
],
|
||||
},
|
||||
},
|
||||
'configurations': {
|
||||
'x86_Base': {
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories':
|
||||
['$(VSInstallDir)/DIA SDK/lib'],
|
||||
},
|
||||
},
|
||||
},
|
||||
'x64_Base': {
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'AdditionalLibraryDirectories':
|
||||
['$(VSInstallDir)/DIA SDK/lib/amd64'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@@ -94,7 +94,7 @@ int PrintMicrodumpProcess(const char* microdump_file,
|
||||
if (machine_readable) {
|
||||
PrintProcessStateMachineReadable(process_state);
|
||||
} else {
|
||||
PrintProcessState(process_state);
|
||||
PrintProcessState(process_state, false, &resolver);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
#include "google_breakpad/processor/minidump_processor.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "processor/logging.h"
|
||||
@@ -51,6 +52,7 @@
|
||||
namespace {
|
||||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::Minidump;
|
||||
using google_breakpad::MinidumpProcessor;
|
||||
using google_breakpad::ProcessState;
|
||||
using google_breakpad::SimpleSymbolSupplier;
|
||||
@@ -68,7 +70,8 @@ using google_breakpad::scoped_ptr;
|
||||
// is printed to stdout.
|
||||
bool PrintMinidumpProcess(const string &minidump_file,
|
||||
const std::vector<string> &symbol_paths,
|
||||
bool machine_readable) {
|
||||
bool machine_readable,
|
||||
bool output_stack_contents) {
|
||||
scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
|
||||
if (!symbol_paths.empty()) {
|
||||
// TODO(mmentovai): check existence of symbol_path if specified?
|
||||
@@ -79,8 +82,13 @@ bool PrintMinidumpProcess(const string &minidump_file,
|
||||
MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
|
||||
|
||||
// Process the minidump.
|
||||
Minidump dump(minidump_file);
|
||||
if (!dump.Read()) {
|
||||
BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
|
||||
return false;
|
||||
}
|
||||
ProcessState process_state;
|
||||
if (minidump_processor.Process(minidump_file, &process_state) !=
|
||||
if (minidump_processor.Process(&dump, &process_state) !=
|
||||
google_breakpad::PROCESS_OK) {
|
||||
BPLOG(ERROR) << "MinidumpProcessor::Process failed";
|
||||
return false;
|
||||
@@ -89,15 +97,16 @@ bool PrintMinidumpProcess(const string &minidump_file,
|
||||
if (machine_readable) {
|
||||
PrintProcessStateMachineReadable(process_state);
|
||||
} else {
|
||||
PrintProcessState(process_state);
|
||||
PrintProcessState(process_state, output_stack_contents, &resolver);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void usage(const char *program_name) {
|
||||
fprintf(stderr, "usage: %s [-m] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n",
|
||||
fprintf(stderr, "usage: %s [-m|-s] <minidump-file> [symbol-path ...]\n"
|
||||
" -m : Output in machine-readable format\n"
|
||||
" -s : Output stack contents\n",
|
||||
program_name);
|
||||
}
|
||||
|
||||
@@ -112,7 +121,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
const char *minidump_file;
|
||||
bool machine_readable;
|
||||
bool machine_readable = false;
|
||||
bool output_stack_contents = false;
|
||||
int symbol_path_arg;
|
||||
|
||||
if (strcmp(argv[1], "-m") == 0) {
|
||||
@@ -124,8 +134,16 @@ int main(int argc, char **argv) {
|
||||
machine_readable = true;
|
||||
minidump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else if (strcmp(argv[1], "-s") == 0) {
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
output_stack_contents = true;
|
||||
minidump_file = argv[2];
|
||||
symbol_path_arg = 3;
|
||||
} else {
|
||||
machine_readable = false;
|
||||
minidump_file = argv[1];
|
||||
symbol_path_arg = 2;
|
||||
}
|
||||
@@ -139,5 +157,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
return PrintMinidumpProcess(minidump_file,
|
||||
symbol_paths,
|
||||
machine_readable) ? 0 : 1;
|
||||
machine_readable,
|
||||
output_stack_contents) ? 0 : 1;
|
||||
}
|
||||
|
@@ -47,6 +47,7 @@
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/code_modules.h"
|
||||
#include "google_breakpad/processor/process_state.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/pathname_stripper.h"
|
||||
@@ -110,6 +111,135 @@ static string StripSeparator(const string &original) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// PrintStackContents prints the stack contents of the current frame to stdout.
|
||||
static void PrintStackContents(const std::string &indent,
|
||||
const StackFrame *frame,
|
||||
const StackFrame *prev_frame,
|
||||
const std::string &cpu,
|
||||
const MemoryRegion *memory,
|
||||
const CodeModules* modules,
|
||||
SourceLineResolverInterface *resolver) {
|
||||
// Find stack range.
|
||||
int word_length = 0;
|
||||
uint64_t stack_begin = 0, stack_end = 0;
|
||||
if (cpu == "x86") {
|
||||
word_length = 4;
|
||||
const StackFrameX86 *frame_x86 = static_cast<const StackFrameX86*>(frame);
|
||||
const StackFrameX86 *prev_frame_x86 =
|
||||
static_cast<const StackFrameX86*>(prev_frame);
|
||||
if ((frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) &&
|
||||
(prev_frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)) {
|
||||
stack_begin = frame_x86->context.esp;
|
||||
stack_end = prev_frame_x86->context.esp;
|
||||
}
|
||||
} else if (cpu == "amd64") {
|
||||
word_length = 8;
|
||||
const StackFrameAMD64 *frame_amd64 =
|
||||
static_cast<const StackFrameAMD64*>(frame);
|
||||
const StackFrameAMD64 *prev_frame_amd64 =
|
||||
static_cast<const StackFrameAMD64*>(prev_frame);
|
||||
if ((frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP) &&
|
||||
(prev_frame_amd64->context_validity &
|
||||
StackFrameAMD64::CONTEXT_VALID_RSP)) {
|
||||
stack_begin = frame_amd64->context.rsp;
|
||||
stack_end = prev_frame_amd64->context.rsp;
|
||||
}
|
||||
} else if (cpu == "arm") {
|
||||
word_length = 4;
|
||||
const StackFrameARM *frame_arm = static_cast<const StackFrameARM*>(frame);
|
||||
const StackFrameARM *prev_frame_arm =
|
||||
static_cast<const StackFrameARM*>(prev_frame);
|
||||
if ((frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP) &&
|
||||
(prev_frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
|
||||
stack_begin = frame_arm->context.iregs[13];
|
||||
stack_end = prev_frame_arm->context.iregs[13];
|
||||
}
|
||||
} else if (cpu == "arm64") {
|
||||
word_length = 8;
|
||||
const StackFrameARM64 *frame_arm64 =
|
||||
static_cast<const StackFrameARM64*>(frame);
|
||||
const StackFrameARM64 *prev_frame_arm64 =
|
||||
static_cast<const StackFrameARM64*>(prev_frame);
|
||||
if ((frame_arm64->context_validity & StackFrameARM64::CONTEXT_VALID_SP) &&
|
||||
(prev_frame_arm64->context_validity &
|
||||
StackFrameARM64::CONTEXT_VALID_SP)) {
|
||||
stack_begin = frame_arm64->context.iregs[31];
|
||||
stack_end = prev_frame_arm64->context.iregs[31];
|
||||
}
|
||||
}
|
||||
if (!word_length || !stack_begin || !stack_end)
|
||||
return;
|
||||
|
||||
// Print stack contents.
|
||||
printf("\n%sStack contents:", indent.c_str());
|
||||
for(uint64_t address = stack_begin; address < stack_end; ) {
|
||||
// Print the start address of this row.
|
||||
if (word_length == 4)
|
||||
printf("\n%s %08x", indent.c_str(), static_cast<uint32_t>(address));
|
||||
else
|
||||
printf("\n%s %016" PRIx64, indent.c_str(), address);
|
||||
|
||||
// Print data in hex.
|
||||
const int kBytesPerRow = 16;
|
||||
std::string data_as_string;
|
||||
for (int i = 0; i < kBytesPerRow; ++i, ++address) {
|
||||
uint8_t value = 0;
|
||||
if (address < stack_end &&
|
||||
memory->GetMemoryAtAddress(address, &value)) {
|
||||
printf(" %02x", value);
|
||||
data_as_string.push_back(isprint(value) ? value : '.');
|
||||
} else {
|
||||
printf(" ");
|
||||
data_as_string.push_back(' ');
|
||||
}
|
||||
}
|
||||
// Print data as string.
|
||||
printf(" %s", data_as_string.c_str());
|
||||
}
|
||||
|
||||
// Try to find instruction pointers from stack.
|
||||
printf("\n%sPossible instruction pointers:\n", indent.c_str());
|
||||
for (uint64_t address = stack_begin; address < stack_end;
|
||||
address += word_length) {
|
||||
StackFrame pointee_frame;
|
||||
|
||||
// Read a word (possible instruction pointer) from stack.
|
||||
if (word_length == 4) {
|
||||
uint32_t data32 = 0;
|
||||
memory->GetMemoryAtAddress(address, &data32);
|
||||
pointee_frame.instruction = data32;
|
||||
} else {
|
||||
uint64_t data64 = 0;
|
||||
memory->GetMemoryAtAddress(address, &data64);
|
||||
pointee_frame.instruction = data64;
|
||||
}
|
||||
pointee_frame.module =
|
||||
modules->GetModuleForAddress(pointee_frame.instruction);
|
||||
|
||||
// Try to look up the function name.
|
||||
if (pointee_frame.module)
|
||||
resolver->FillSourceLineInfo(&pointee_frame);
|
||||
|
||||
// Print function name.
|
||||
if (!pointee_frame.function_name.empty()) {
|
||||
if (word_length == 4) {
|
||||
printf("%s *(0x%08x) = 0x%08x", indent.c_str(),
|
||||
static_cast<uint32_t>(address),
|
||||
static_cast<uint32_t>(pointee_frame.instruction));
|
||||
} else {
|
||||
printf("%s *(0x%016" PRIx64 ") = 0x%016" PRIx64,
|
||||
indent.c_str(), address, pointee_frame.instruction);
|
||||
}
|
||||
printf(" <%s> [%s : %d + 0x%" PRIx64 "]\n",
|
||||
pointee_frame.function_name.c_str(),
|
||||
PathnameStripper::File(pointee_frame.source_file_name).c_str(),
|
||||
pointee_frame.source_line,
|
||||
pointee_frame.instruction - pointee_frame.source_line_base);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// PrintStack prints the call stack in |stack| to stdout, in a reasonably
|
||||
// useful form. Module, function, and source file names are displayed if
|
||||
// they are available. The code offset to the base code address of the
|
||||
@@ -119,7 +249,12 @@ static string StripSeparator(const string &original) {
|
||||
//
|
||||
// If |cpu| is a recognized CPU name, relevant register state for each stack
|
||||
// frame printed is also output, if available.
|
||||
static void PrintStack(const CallStack *stack, const string &cpu) {
|
||||
static void PrintStack(const CallStack *stack,
|
||||
const string &cpu,
|
||||
bool output_stack_contents,
|
||||
const MemoryRegion* memory,
|
||||
const CodeModules* modules,
|
||||
SourceLineResolverInterface* resolver) {
|
||||
int frame_count = stack->frames()->size();
|
||||
if (frame_count == 0) {
|
||||
printf(" <no frames>\n");
|
||||
@@ -469,6 +604,13 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
|
||||
sequence);
|
||||
}
|
||||
printf("\n Found by: %s\n", frame->trust_description().c_str());
|
||||
|
||||
// Print stack contents.
|
||||
if (output_stack_contents && frame_index + 1 < frame_count) {
|
||||
const std::string indent(" ");
|
||||
PrintStackContents(indent, frame, stack->frames()->at(frame_index + 1),
|
||||
cpu, memory, modules, resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +784,9 @@ static void PrintModulesMachineReadable(const CodeModules *modules) {
|
||||
|
||||
} // namespace
|
||||
|
||||
void PrintProcessState(const ProcessState& process_state) {
|
||||
void PrintProcessState(const ProcessState& process_state,
|
||||
bool output_stack_contents,
|
||||
SourceLineResolverInterface* resolver) {
|
||||
// Print OS and CPU information.
|
||||
string cpu = process_state.system_info()->cpu;
|
||||
string cpu_info = process_state.system_info()->cpu_info;
|
||||
@@ -692,7 +836,10 @@ void PrintProcessState(const ProcessState& process_state) {
|
||||
requesting_thread,
|
||||
process_state.crashed() ? "crashed" :
|
||||
"requested dump, did not crash");
|
||||
PrintStack(process_state.threads()->at(requesting_thread), cpu);
|
||||
PrintStack(process_state.threads()->at(requesting_thread), cpu,
|
||||
output_stack_contents,
|
||||
process_state.thread_memory_regions()->at(requesting_thread),
|
||||
process_state.modules(), resolver);
|
||||
}
|
||||
|
||||
// Print all of the threads in the dump.
|
||||
@@ -702,7 +849,10 @@ void PrintProcessState(const ProcessState& process_state) {
|
||||
// Don't print the crash thread again, it was already printed.
|
||||
printf("\n");
|
||||
printf("Thread %d\n", thread_index);
|
||||
PrintStack(process_state.threads()->at(thread_index), cpu);
|
||||
PrintStack(process_state.threads()->at(thread_index), cpu,
|
||||
output_stack_contents,
|
||||
process_state.thread_memory_regions()->at(thread_index),
|
||||
process_state.modules(), resolver);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,9 +37,12 @@
|
||||
namespace google_breakpad {
|
||||
|
||||
class ProcessState;
|
||||
class SourceLineResolverInterface;
|
||||
|
||||
void PrintProcessStateMachineReadable(const ProcessState& process_state);
|
||||
void PrintProcessState(const ProcessState& process_state);
|
||||
void PrintProcessState(const ProcessState& process_state,
|
||||
bool output_stack_contents,
|
||||
SourceLineResolverInterface* resolver);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
Reference in New Issue
Block a user