Skip to content
This repository was archived by the owner on Jun 30, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

Abhishek Dasgupta <[email protected]>
Abhishek Parmar <[email protected]>
Andrew Schwartzmeyer <[email protected]>
Andy Ying <[email protected]>
Brian Silverman <[email protected]>
Google Inc.
Expand Down
9 changes: 7 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,9 @@ set (GLOG_SRCS
src/vlog_is_on.cc
)

if (HAVE_PTHREAD)
if (HAVE_PTHREAD OR WIN32)
list (APPEND GLOG_SRCS src/signalhandler.cc)
endif (HAVE_PTHREAD)
endif (HAVE_PTHREAD OR WIN32)

if (WIN32)
list (APPEND GLOG_SRCS
Expand Down Expand Up @@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H)
set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_H)

if (WIN32)
set (HAVE_STACKTRACE 1)
set (HAVE_SYMBOLIZE 1)
endif (WIN32)

if (UNIX OR (APPLE AND HAVE_DLADDR))
set (HAVE_SYMBOLIZE 1)
endif (UNIX OR (APPLE AND HAVE_DLADDR))
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

Abhishek Dasgupta <[email protected]>
Abhishek Parmar <[email protected]>
Andrew Schwartzmeyer <[email protected]>
Andy Ying <[email protected]>
Brian Silverman <[email protected]>
Fumitoshi Ukai <[email protected]>
Expand Down
32 changes: 32 additions & 0 deletions src/demangle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@
// Note that we only have partial C++0x support yet.

#include <stdio.h> // for NULL
#include "utilities.h"
#include "demangle.h"

#if defined(OS_WINDOWS)
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp")
#endif

_START_GOOGLE_NAMESPACE_

#if !defined(OS_WINDOWS)
typedef struct {
const char *abbrev;
const char *real_name;
Expand Down Expand Up @@ -1293,12 +1300,37 @@ static bool ParseTopLevelMangledName(State *state) {
}
return false;
}
#endif

// The demangler entry point.
bool Demangle(const char *mangled, char *out, int out_size) {
#if defined(OS_WINDOWS)
// When built with incremental linking, the Windows debugger
// library provides a more complicated `Symbol->Name` with the
// Incremental Linking Table offset, which looks like
// `@ILT+1105(?func@Foo@@SAXH@Z)`. However, the demangler expects
// only the mangled symbol, `?func@Foo@@SAXH@Z`. Fortunately, the
// mangled symbol is guaranteed not to have parentheses,
// so we search for `(` and extract up to `)`.
//
// Since we may be in a signal handler here, we cannot use `std::string`.
char buffer[1024]; // Big enough for a sane symbol.
const char *lparen = strchr(mangled, '(');
if (lparen) {
// Extract the string `(?...)`
const char *rparen = strchr(lparen, ')');
size_t length = rparen - lparen - 1;
strncpy(buffer, lparen + 1, length);
buffer[length] = '\0';
mangled = buffer;
} // Else the symbol wasn't inside a set of parentheses
// We use the ANSI version to ensure the string type is always `char *`.
return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE);
#else
State state;
InitState(&state, mangled, out, out_size);
return ParseTopLevelMangledName(&state) && !state.overflowed;
#endif
}

_END_GOOGLE_NAMESPACE_
41 changes: 31 additions & 10 deletions src/demangle_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,37 @@ static const char *DemangleIt(const char * const mangled) {
}
}

#if defined(OS_WINDOWS)

TEST(Demangle, Windows) {
EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("?func@Foo@@SAXH@Z"));
EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
EXPECT_STREQ(
"int __cdecl foobarArray(int * const)",
DemangleIt("?foobarArray@@YAHQAH@Z"));
}

#else

// Test corner cases of bounary conditions.
TEST(Demangle, CornerCases) {
char tmp[10];
EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp)));
// sizeof("foobar()") == 9
EXPECT_STREQ("foobar()", tmp);
EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9));
EXPECT_STREQ("foobar()", tmp);
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8)); // Not enough.
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1));
EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0));
EXPECT_FALSE(Demangle("_Z6foobarv", NULL, 0)); // Should not cause SEGV.
const size_t size = 10;
char tmp[size] = { 0 };
const char *demangled = "foobar()";
const char *mangled = "_Z6foobarv";
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
// sizeof("foobar()") == size - 1
EXPECT_STREQ(demangled, tmp);
EXPECT_TRUE(Demangle(mangled, tmp, size - 1));
EXPECT_STREQ(demangled, tmp);
EXPECT_FALSE(Demangle(mangled, tmp, size - 2)); // Not enough.
EXPECT_FALSE(Demangle(mangled, tmp, 1));
EXPECT_FALSE(Demangle(mangled, tmp, 0));
EXPECT_FALSE(Demangle(mangled, NULL, 0)); // Should not cause SEGV.
}

// Test handling of functions suffixed with .clone.N, which is used by GCC
Expand Down Expand Up @@ -123,6 +142,8 @@ TEST(Demangle, FromFile) {
}
}

#endif

int main(int argc, char **argv) {
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
Expand Down
9 changes: 3 additions & 6 deletions src/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason(
# define ATTRIBUTE_NORETURN
#endif

#if defined(OS_WINDOWS)
__declspec(noreturn)
#endif
static void logging_fail() ATTRIBUTE_NORETURN;

static void logging_fail() {
#if defined(_DEBUG) && defined(_MSC_VER)
// When debugging on windows, avoid the obnoxious dialog and make
// it possible to continue past a LOG(FATAL) in the debugger
__debugbreak();
#else
abort();
#endif
}

typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
Expand Down
42 changes: 35 additions & 7 deletions src/signalhandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@

_START_GOOGLE_NAMESPACE_

// TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION

namespace {

// We'll install the failure signal handler for these signals. We could
Expand All @@ -66,10 +63,14 @@ const struct {
{ SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(OS_WINDOWS)
{ SIGBUS, "SIGBUS" },
#endif
{ SIGTERM, "SIGTERM" },
};

static bool kFailureSignalHandlerInstalled = false;

// Returns the program counter from signal context, NULL if unknown.
void* GetPC(void* ucontext_in_void) {
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
Expand Down Expand Up @@ -168,6 +169,9 @@ void DumpTimeInfo() {
g_failure_writer(buf, formatter.num_bytes_written());
}

// TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION

// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name.
Expand Down Expand Up @@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
g_failure_writer(buf, formatter.num_bytes_written());
}

#endif // HAVE_SIGACTION

// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name.
Expand Down Expand Up @@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {

// Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) {
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(signal_number, &sig_action, NULL);
kill(getpid(), signal_number);
#elif defined(OS_WINDOWS)
signal(signal_number, SIG_DFL);
raise(signal_number);
#endif
}

// This variable is used for protecting FailureSignalHandler() from
Expand All @@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL;

// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
#if defined(OS_WINDOWS)
void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number,
siginfo_t *signal_info,
void *ucontext) {
void *ucontext)
#endif
{
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
Expand Down Expand Up @@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number,
// First dump time info.
DumpTimeInfo();

#if !defined(OS_WINDOWS)
// Get the program counter from ucontext.
void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc);
#endif

#ifdef HAVE_STACKTRACE
// Get the stack traces.
void *stack[32];
// +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info);
# endif
// Dump the stack traces.
for (int i = 0; i < depth; ++i) {
DumpStackFrameInfo(" ", stack[i]);
Expand All @@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number,

} // namespace

#endif // HAVE_SIGACTION

namespace glog_internal_namespace_ {

bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sigaction(SIGABRT, NULL, &sig_action);
if (sig_action.sa_sigaction == &FailureSignalHandler)
return true;
#elif defined(OS_WINDOWS)
return kFailureSignalHandlerInstalled;
#endif // HAVE_SIGACTION
return false;
}
Expand All @@ -363,11 +384,18 @@ void InstallFailureSignalHandler() {
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
}
kFailureSignalHandlerInstalled = true;
#elif defined(OS_WINDOWS)
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
SIG_ERR);
}
kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION
}

void InstallFailureWriter(void (*writer)(const char* data, int size)) {
#ifdef HAVE_SIGACTION
#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
g_failure_writer = writer;
#endif // HAVE_SIGACTION
}
Expand Down
12 changes: 11 additions & 1 deletion src/signalhandler_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@

#include "utilities.h"

#include <pthread.h>
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -87,12 +89,20 @@ int main(int argc, char **argv) {
fprintf(stderr, "looping\n");
while (true);
} else if (command == "die_in_thread") {
#if defined(HAVE_PTHREAD)
pthread_t thread;
pthread_create(&thread, NULL, &DieInThread, NULL);
pthread_join(thread, NULL);
#else
fprintf(stderr, "no pthread\n");
return 1;
#endif
} else if (command == "dump_to_stdout") {
InstallFailureWriter(WriteToStdout);
abort();
} else if (command == "installed") {
fprintf(stderr, "signal handler installed: %s\n",
IsFailureSignalHandlerInstalled() ? "true" : "false");
} else {
// Tell the shell script
puts("OK");
Expand Down
51 changes: 51 additions & 0 deletions src/stacktrace_windows-inl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) 2000 - 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Andrew Schwartzmeyer
//
// Windows implementation - just use CaptureStackBackTrace

#include "config.h"
#include "port.h"
#include "stacktrace.h"
#include <DbgHelp.h>

_START_GOOGLE_NAMESPACE_

GOOGLE_GLOG_DLL_DECL
int GetStackTrace(void** result, int max_depth, int skip_count) {
if (max_depth > 64) {
max_depth = 64;
}
skip_count++; // we want to skip the current frame as well
// This API is thread-safe (moreover it walks only the current thread).
return CaptureStackBackTrace(skip_count, max_depth, result, NULL);
}

_END_GOOGLE_NAMESPACE_
Loading