Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
G
glog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
glog
Commits
5cfa9a28
Commit
5cfa9a28
authored
Jun 28, 2017
by
Shinichiro Hamaji
Committed by
GitHub
Jun 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #168 from andschwa/windows-stacktrace
Port stack tracing to Windows
parents
77a0e36b
d1f49ba5
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
299 additions
and
50 deletions
+299
-50
AUTHORS
AUTHORS
+1
-0
CMakeLists.txt
CMakeLists.txt
+7
-2
CONTRIBUTORS
CONTRIBUTORS
+1
-0
demangle.cc
src/demangle.cc
+32
-0
demangle_unittest.cc
src/demangle_unittest.cc
+31
-10
logging.cc
src/logging.cc
+3
-6
signalhandler.cc
src/signalhandler.cc
+35
-7
signalhandler_unittest.cc
src/signalhandler_unittest.cc
+11
-1
stacktrace_windows-inl.h
src/stacktrace_windows-inl.h
+51
-0
symbolize.cc
src/symbolize.cc
+61
-0
symbolize_unittest.cc
src/symbolize_unittest.cc
+52
-22
utilities.cc
src/utilities.cc
+4
-2
utilities.h
src/utilities.h
+10
-0
No files found.
AUTHORS
View file @
5cfa9a28
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Parmar <abhishek@orng.net>
Abhishek Parmar <abhishek@orng.net>
Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Andy Ying <andy@trailofbits.com>
Andy Ying <andy@trailofbits.com>
Brian Silverman <bsilver16384@gmail.com>
Brian Silverman <bsilver16384@gmail.com>
Google Inc.
Google Inc.
...
...
CMakeLists.txt
View file @
5cfa9a28
...
@@ -364,9 +364,9 @@ set (GLOG_SRCS
...
@@ -364,9 +364,9 @@ set (GLOG_SRCS
src/vlog_is_on.cc
src/vlog_is_on.cc
)
)
if (HAVE_PTHREAD)
if (HAVE_PTHREAD
OR WIN32
)
list (APPEND GLOG_SRCS src/signalhandler.cc)
list (APPEND GLOG_SRCS src/signalhandler.cc)
endif (HAVE_PTHREAD)
endif (HAVE_PTHREAD
OR WIN32
)
if (WIN32)
if (WIN32)
list (APPEND GLOG_SRCS
list (APPEND GLOG_SRCS
...
@@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H)
...
@@ -455,6 +455,11 @@ if (HAVE_EXECINFO_H)
set
(
HAVE_STACKTRACE 1
)
set
(
HAVE_STACKTRACE 1
)
endif
(
HAVE_EXECINFO_H
)
endif
(
HAVE_EXECINFO_H
)
if
(
WIN32
)
set
(
HAVE_STACKTRACE 1
)
set
(
HAVE_SYMBOLIZE 1
)
endif
(
WIN32
)
if
(
UNIX
OR
(
APPLE AND HAVE_DLADDR
))
if
(
UNIX
OR
(
APPLE AND HAVE_DLADDR
))
set
(
HAVE_SYMBOLIZE 1
)
set
(
HAVE_SYMBOLIZE 1
)
endif
(
UNIX
OR
(
APPLE AND HAVE_DLADDR
))
endif
(
UNIX
OR
(
APPLE AND HAVE_DLADDR
))
...
...
CONTRIBUTORS
View file @
5cfa9a28
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Dasgupta <abhi2743@gmail.com>
Abhishek Parmar <abhishek@orng.net>
Abhishek Parmar <abhishek@orng.net>
Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Andy Ying <andy@trailofbits.com>
Andy Ying <andy@trailofbits.com>
Brian Silverman <bsilver16384@gmail.com>
Brian Silverman <bsilver16384@gmail.com>
Fumitoshi Ukai <ukai@google.com>
Fumitoshi Ukai <ukai@google.com>
...
...
src/demangle.cc
View file @
5cfa9a28
...
@@ -35,10 +35,17 @@
...
@@ -35,10 +35,17 @@
// Note that we only have partial C++0x support yet.
// Note that we only have partial C++0x support yet.
#include <stdio.h> // for NULL
#include <stdio.h> // for NULL
#include "utilities.h"
#include "demangle.h"
#include "demangle.h"
#if defined(OS_WINDOWS)
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp")
#endif
_START_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_
#if !defined(OS_WINDOWS)
typedef
struct
{
typedef
struct
{
const
char
*
abbrev
;
const
char
*
abbrev
;
const
char
*
real_name
;
const
char
*
real_name
;
...
@@ -1293,12 +1300,37 @@ static bool ParseTopLevelMangledName(State *state) {
...
@@ -1293,12 +1300,37 @@ static bool ParseTopLevelMangledName(State *state) {
}
}
return
false
;
return
false
;
}
}
#endif
// The demangler entry point.
// The demangler entry point.
bool
Demangle
(
const
char
*
mangled
,
char
*
out
,
int
out_size
)
{
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
;
State
state
;
InitState
(
&
state
,
mangled
,
out
,
out_size
);
InitState
(
&
state
,
mangled
,
out
,
out_size
);
return
ParseTopLevelMangledName
(
&
state
)
&&
!
state
.
overflowed
;
return
ParseTopLevelMangledName
(
&
state
)
&&
!
state
.
overflowed
;
#endif
}
}
_END_GOOGLE_NAMESPACE_
_END_GOOGLE_NAMESPACE_
src/demangle_unittest.cc
View file @
5cfa9a28
...
@@ -62,18 +62,37 @@ static const char *DemangleIt(const char * const mangled) {
...
@@ -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 corner cases of bounary conditions.
TEST
(
Demangle
,
CornerCases
)
{
TEST
(
Demangle
,
CornerCases
)
{
char
tmp
[
10
];
const
size_t
size
=
10
;
EXPECT_TRUE
(
Demangle
(
"_Z6foobarv"
,
tmp
,
sizeof
(
tmp
)));
char
tmp
[
size
]
=
{
0
};
// sizeof("foobar()") == 9
const
char
*
demangled
=
"foobar()"
;
EXPECT_STREQ
(
"foobar()"
,
tmp
);
const
char
*
mangled
=
"_Z6foobarv"
;
EXPECT_TRUE
(
Demangle
(
"_Z6foobarv"
,
tmp
,
9
));
EXPECT_TRUE
(
Demangle
(
mangled
,
tmp
,
sizeof
(
tmp
)));
EXPECT_STREQ
(
"foobar()"
,
tmp
);
// sizeof("foobar()") == size - 1
EXPECT_FALSE
(
Demangle
(
"_Z6foobarv"
,
tmp
,
8
));
// Not enough.
EXPECT_STREQ
(
demangled
,
tmp
);
EXPECT_FALSE
(
Demangle
(
"_Z6foobarv"
,
tmp
,
1
));
EXPECT_TRUE
(
Demangle
(
mangled
,
tmp
,
size
-
1
));
EXPECT_FALSE
(
Demangle
(
"_Z6foobarv"
,
tmp
,
0
));
EXPECT_STREQ
(
demangled
,
tmp
);
EXPECT_FALSE
(
Demangle
(
"_Z6foobarv"
,
NULL
,
0
));
// Should not cause SEGV.
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
// Test handling of functions suffixed with .clone.N, which is used by GCC
...
@@ -123,6 +142,8 @@ TEST(Demangle, FromFile) {
...
@@ -123,6 +142,8 @@ TEST(Demangle, FromFile) {
}
}
}
}
#endif
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
#ifdef HAVE_LIB_GFLAGS
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
...
...
src/logging.cc
View file @
5cfa9a28
...
@@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason(
...
@@ -1463,16 +1463,13 @@ void LogMessage::RecordCrashReason(
# define ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN
#endif
#endif
#if defined(OS_WINDOWS)
__declspec
(
noreturn
)
#endif
static
void
logging_fail
()
ATTRIBUTE_NORETURN
;
static
void
logging_fail
()
ATTRIBUTE_NORETURN
;
static
void
logging_fail
()
{
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
();
abort
();
#endif
}
}
typedef
void
(
*
logging_fail_func_t
)()
ATTRIBUTE_NORETURN
;
typedef
void
(
*
logging_fail_func_t
)()
ATTRIBUTE_NORETURN
;
...
...
src/signalhandler.cc
View file @
5cfa9a28
...
@@ -48,9 +48,6 @@
...
@@ -48,9 +48,6 @@
_START_GOOGLE_NAMESPACE_
_START_GOOGLE_NAMESPACE_
// TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION
namespace
{
namespace
{
// We'll install the failure signal handler for these signals. We could
// We'll install the failure signal handler for these signals. We could
...
@@ -66,10 +63,14 @@ const struct {
...
@@ -66,10 +63,14 @@ const struct {
{
SIGILL
,
"SIGILL"
},
{
SIGILL
,
"SIGILL"
},
{
SIGFPE
,
"SIGFPE"
},
{
SIGFPE
,
"SIGFPE"
},
{
SIGABRT
,
"SIGABRT"
},
{
SIGABRT
,
"SIGABRT"
},
#if !defined(OS_WINDOWS)
{
SIGBUS
,
"SIGBUS"
},
{
SIGBUS
,
"SIGBUS"
},
#endif
{
SIGTERM
,
"SIGTERM"
},
{
SIGTERM
,
"SIGTERM"
},
};
};
static
bool
kFailureSignalHandlerInstalled
=
false
;
// Returns the program counter from signal context, NULL if unknown.
// Returns the program counter from signal context, NULL if unknown.
void
*
GetPC
(
void
*
ucontext_in_void
)
{
void
*
GetPC
(
void
*
ucontext_in_void
)
{
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
...
@@ -168,6 +169,9 @@ void DumpTimeInfo() {
...
@@ -168,6 +169,9 @@ void DumpTimeInfo() {
g_failure_writer
(
buf
,
formatter
.
num_bytes_written
());
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.
// Dumps information about the signal to STDERR.
void
DumpSignalInfo
(
int
signal_number
,
siginfo_t
*
siginfo
)
{
void
DumpSignalInfo
(
int
signal_number
,
siginfo_t
*
siginfo
)
{
// Get the signal name.
// Get the signal name.
...
@@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
...
@@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
g_failure_writer
(
buf
,
formatter
.
num_bytes_written
());
g_failure_writer
(
buf
,
formatter
.
num_bytes_written
());
}
}
#endif // HAVE_SIGACTION
// Dumps information about the stack frame to STDERR.
// Dumps information about the stack frame to STDERR.
void
DumpStackFrameInfo
(
const
char
*
prefix
,
void
*
pc
)
{
void
DumpStackFrameInfo
(
const
char
*
prefix
,
void
*
pc
)
{
// Get the symbol name.
// Get the symbol name.
...
@@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
...
@@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) {
// Invoke the default signal handler.
// Invoke the default signal handler.
void
InvokeDefaultSignalHandler
(
int
signal_number
)
{
void
InvokeDefaultSignalHandler
(
int
signal_number
)
{
#ifdef HAVE_SIGACTION
struct
sigaction
sig_action
;
struct
sigaction
sig_action
;
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
sigemptyset
(
&
sig_action
.
sa_mask
);
sigemptyset
(
&
sig_action
.
sa_mask
);
sig_action
.
sa_handler
=
SIG_DFL
;
sig_action
.
sa_handler
=
SIG_DFL
;
sigaction
(
signal_number
,
&
sig_action
,
NULL
);
sigaction
(
signal_number
,
&
sig_action
,
NULL
);
kill
(
getpid
(),
signal_number
);
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
// This variable is used for protecting FailureSignalHandler() from
...
@@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL;
...
@@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL;
// Dumps signal and stack frame information, and invokes the default
// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
// signal handler once our job is done.
#if defined(OS_WINDOWS)
void
FailureSignalHandler
(
int
signal_number
)
#else
void
FailureSignalHandler
(
int
signal_number
,
void
FailureSignalHandler
(
int
signal_number
,
siginfo_t
*
signal_info
,
siginfo_t
*
signal_info
,
void
*
ucontext
)
{
void
*
ucontext
)
#endif
{
// First check if we've already entered the function. We use an atomic
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
// platforms, we use a naive method that could lead to a subtle race.
...
@@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number,
...
@@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number,
// First dump time info.
// First dump time info.
DumpTimeInfo
();
DumpTimeInfo
();
#if !defined(OS_WINDOWS)
// Get the program counter from ucontext.
// Get the program counter from ucontext.
void
*
pc
=
GetPC
(
ucontext
);
void
*
pc
=
GetPC
(
ucontext
);
DumpStackFrameInfo
(
"PC: "
,
pc
);
DumpStackFrameInfo
(
"PC: "
,
pc
);
#endif
#ifdef HAVE_STACKTRACE
#ifdef HAVE_STACKTRACE
// Get the stack traces.
// Get the stack traces.
void
*
stack
[
32
];
void
*
stack
[
32
];
// +1 to exclude this function.
// +1 to exclude this function.
const
int
depth
=
GetStackTrace
(
stack
,
ARRAYSIZE
(
stack
),
1
);
const
int
depth
=
GetStackTrace
(
stack
,
ARRAYSIZE
(
stack
),
1
);
# ifdef HAVE_SIGACTION
DumpSignalInfo
(
signal_number
,
signal_info
);
DumpSignalInfo
(
signal_number
,
signal_info
);
# endif
// Dump the stack traces.
// Dump the stack traces.
for
(
int
i
=
0
;
i
<
depth
;
++
i
)
{
for
(
int
i
=
0
;
i
<
depth
;
++
i
)
{
DumpStackFrameInfo
(
" "
,
stack
[
i
]);
DumpStackFrameInfo
(
" "
,
stack
[
i
]);
...
@@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number,
...
@@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number,
}
// namespace
}
// namespace
#endif // HAVE_SIGACTION
namespace
glog_internal_namespace_
{
namespace
glog_internal_namespace_
{
bool
IsFailureSignalHandlerInstalled
()
{
bool
IsFailureSignalHandlerInstalled
()
{
#ifdef HAVE_SIGACTION
#ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
struct
sigaction
sig_action
;
struct
sigaction
sig_action
;
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
sigemptyset
(
&
sig_action
.
sa_mask
);
sigemptyset
(
&
sig_action
.
sa_mask
);
sigaction
(
SIGABRT
,
NULL
,
&
sig_action
);
sigaction
(
SIGABRT
,
NULL
,
&
sig_action
);
if
(
sig_action
.
sa_sigaction
==
&
FailureSignalHandler
)
if
(
sig_action
.
sa_sigaction
==
&
FailureSignalHandler
)
return
true
;
return
true
;
#elif defined(OS_WINDOWS)
return
kFailureSignalHandlerInstalled
;
#endif // HAVE_SIGACTION
#endif // HAVE_SIGACTION
return
false
;
return
false
;
}
}
...
@@ -363,11 +384,18 @@ void InstallFailureSignalHandler() {
...
@@ -363,11 +384,18 @@ void InstallFailureSignalHandler() {
for
(
size_t
i
=
0
;
i
<
ARRAYSIZE
(
kFailureSignals
);
++
i
)
{
for
(
size_t
i
=
0
;
i
<
ARRAYSIZE
(
kFailureSignals
);
++
i
)
{
CHECK_ERR
(
sigaction
(
kFailureSignals
[
i
].
number
,
&
sig_action
,
NULL
));
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
#endif // HAVE_SIGACTION
}
}
void
InstallFailureWriter
(
void
(
*
writer
)(
const
char
*
data
,
int
size
))
{
void
InstallFailureWriter
(
void
(
*
writer
)(
const
char
*
data
,
int
size
))
{
#if
def HAVE_SIGACTION
#if
defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
g_failure_writer
=
writer
;
g_failure_writer
=
writer
;
#endif // HAVE_SIGACTION
#endif // HAVE_SIGACTION
}
}
...
...
src/signalhandler_unittest.cc
View file @
5cfa9a28
...
@@ -34,7 +34,9 @@
...
@@ -34,7 +34,9 @@
#include "utilities.h"
#include "utilities.h"
#include <pthread.h>
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <signal.h>
#include <signal.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
...
@@ -87,12 +89,20 @@ int main(int argc, char **argv) {
...
@@ -87,12 +89,20 @@ int main(int argc, char **argv) {
fprintf
(
stderr
,
"looping
\n
"
);
fprintf
(
stderr
,
"looping
\n
"
);
while
(
true
);
while
(
true
);
}
else
if
(
command
==
"die_in_thread"
)
{
}
else
if
(
command
==
"die_in_thread"
)
{
#if defined(HAVE_PTHREAD)
pthread_t
thread
;
pthread_t
thread
;
pthread_create
(
&
thread
,
NULL
,
&
DieInThread
,
NULL
);
pthread_create
(
&
thread
,
NULL
,
&
DieInThread
,
NULL
);
pthread_join
(
thread
,
NULL
);
pthread_join
(
thread
,
NULL
);
#else
fprintf
(
stderr
,
"no pthread
\n
"
);
return
1
;
#endif
}
else
if
(
command
==
"dump_to_stdout"
)
{
}
else
if
(
command
==
"dump_to_stdout"
)
{
InstallFailureWriter
(
WriteToStdout
);
InstallFailureWriter
(
WriteToStdout
);
abort
();
abort
();
}
else
if
(
command
==
"installed"
)
{
fprintf
(
stderr
,
"signal handler installed: %s
\n
"
,
IsFailureSignalHandlerInstalled
()
?
"true"
:
"false"
);
}
else
{
}
else
{
// Tell the shell script
// Tell the shell script
puts
(
"OK"
);
puts
(
"OK"
);
...
...
src/stacktrace_windows-inl.h
0 → 100644
View file @
5cfa9a28
// 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_
src/symbolize.cc
View file @
5cfa9a28
...
@@ -837,6 +837,67 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
...
@@ -837,6 +837,67 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
_END_GOOGLE_NAMESPACE_
_END_GOOGLE_NAMESPACE_
#elif defined(OS_WINDOWS)
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp")
_START_GOOGLE_NAMESPACE_
class
SymInitializer
{
public
:
HANDLE
process
=
NULL
;
bool
ready
=
false
;
SymInitializer
()
{
// Initialize the symbol handler.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
process
=
GetCurrentProcess
();
// Defer symbol loading.
// We do not request undecorated symbols with SYMOPT_UNDNAME
// because the mangling library calls UnDecorateSymbolName.
SymSetOptions
(
SYMOPT_DEFERRED_LOADS
);
if
(
SymInitialize
(
process
,
NULL
,
true
))
{
ready
=
true
;
}
}
~
SymInitializer
()
{
SymCleanup
(
process
);
// We do not need to close `HANDLE process` because it's a "pseudo handle."
}
private
:
SymInitializer
(
const
SymInitializer
&
);
SymInitializer
&
operator
=
(
const
SymInitializer
&
);
};
static
ATTRIBUTE_NOINLINE
bool
SymbolizeAndDemangle
(
void
*
pc
,
char
*
out
,
int
out_size
)
{
const
static
SymInitializer
symInitializer
;
if
(
!
symInitializer
.
ready
)
{
return
false
;
}
// Resolve symbol information from address.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
char
buf
[
sizeof
(
SYMBOL_INFO
)
+
MAX_SYM_NAME
];
SYMBOL_INFO
*
symbol
=
reinterpret_cast
<
SYMBOL_INFO
*>
(
buf
);
symbol
->
SizeOfStruct
=
sizeof
(
SYMBOL_INFO
);
symbol
->
MaxNameLen
=
MAX_SYM_NAME
;
// We use the ANSI version to ensure the string type is always `char *`.
// This could break if a symbol has Unicode in it.
BOOL
ret
=
SymFromAddr
(
symInitializer
.
process
,
reinterpret_cast
<
DWORD64
>
(
pc
),
0
,
symbol
);
if
(
ret
==
1
&&
static_cast
<
int
>
(
symbol
->
NameLen
)
<
out_size
)
{
// `NameLen` does not include the null terminating character.
strncpy
(
out
,
symbol
->
Name
,
static_cast
<
size_t
>
(
symbol
->
NameLen
)
+
1
);
out
[
static_cast
<
size_t
>
(
symbol
->
NameLen
)]
=
'\0'
;
// Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace
(
out
,
out_size
);
return
true
;
}
return
false
;
}
_END_GOOGLE_NAMESPACE_
#else
#else
# error BUG: HAVE_SYMBOLIZE was wrongly set
# error BUG: HAVE_SYMBOLIZE was wrongly set
#endif
#endif
...
...
src/symbolize_unittest.cc
View file @
5cfa9a28
...
@@ -49,10 +49,22 @@ using namespace GFLAGS_NAMESPACE;
...
@@ -49,10 +49,22 @@ using namespace GFLAGS_NAMESPACE;
using
namespace
std
;
using
namespace
std
;
using
namespace
GOOGLE_NAMESPACE
;
using
namespace
GOOGLE_NAMESPACE
;
#if defined(HAVE_STACKTRACE)
&& defined(__ELF__)
#if defined(HAVE_STACKTRACE)
#define always_inline
#define always_inline
// A wrapper function for Symbolize() to make the unit test simple.
static
const
char
*
TrySymbolize
(
void
*
pc
)
{
static
char
symbol
[
4096
];
if
(
Symbolize
(
pc
,
symbol
,
sizeof
(
symbol
)))
{
return
symbol
;
}
else
{
return
NULL
;
}
}
# if defined(__ELF__)
// This unit tests make sense only with GCC.
// This unit tests make sense only with GCC.
// Uses lots of GCC specific features.
// Uses lots of GCC specific features.
#if defined(__GNUC__) && !defined(__OPENCC__)
#if defined(__GNUC__) && !defined(__OPENCC__)
...
@@ -70,16 +82,6 @@ using namespace GOOGLE_NAMESPACE;
...
@@ -70,16 +82,6 @@ using namespace GOOGLE_NAMESPACE;
# endif // defined(__i386__) || defined(__x86_64__)
# endif // defined(__i386__) || defined(__x86_64__)
#endif
#endif
// A wrapper function for Symbolize() to make the unit test simple.
static
const
char
*
TrySymbolize
(
void
*
pc
)
{
static
char
symbol
[
4096
];
if
(
Symbolize
(
pc
,
symbol
,
sizeof
(
symbol
)))
{
return
symbol
;
}
else
{
return
NULL
;
}
}
// Make them C linkage to avoid mangled names.
// Make them C linkage to avoid mangled names.
extern
"C"
{
extern
"C"
{
void
nonstatic_func
()
{
void
nonstatic_func
()
{
...
@@ -355,11 +357,42 @@ void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
...
@@ -355,11 +357,42 @@ void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#endif
#endif
}
}
# elif defined(OS_WINDOWS)
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
struct
Foo
{
static
void
func
(
int
x
);
};
__declspec
(
noinline
)
void
Foo
::
func
(
int
x
)
{
volatile
int
a
=
x
;
++
a
;
}
TEST
(
Symbolize
,
SymbolizeWithDemangling
)
{
Foo
::
func
(
100
);
const
char
*
ret
=
TrySymbolize
((
void
*
)(
&
Foo
::
func
));
EXPECT_STREQ
(
"public: static void __cdecl Foo::func(int)"
,
ret
);
}
__declspec
(
noinline
)
void
TestWithReturnAddress
()
{
void
*
return_address
=
_ReturnAddress
();
const
char
*
symbol
=
TrySymbolize
(
return_address
);
CHECK
(
symbol
!=
NULL
);
CHECK_STREQ
(
symbol
,
"main"
);
cout
<<
"Test case TestWithReturnAddress passed."
<<
endl
;
}
# endif // __ELF__
#endif // HAVE_STACKTRACE
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
FLAGS_logtostderr
=
true
;
FLAGS_logtostderr
=
true
;
InitGoogleLogging
(
argv
[
0
]);
InitGoogleLogging
(
argv
[
0
]);
InitGoogleTest
(
&
argc
,
argv
);
InitGoogleTest
(
&
argc
,
argv
);
#ifdef HAVE_SYMBOLIZE
#if defined(HAVE_SYMBOLIZE)
# if defined(__ELF__)
// We don't want to get affected by the callback interface, that may be
// We don't want to get affected by the callback interface, that may be
// used to install some callback function at InitGoogle() time.
// used to install some callback function at InitGoogle() time.
InstallSymbolizeCallback
(
NULL
);
InstallSymbolizeCallback
(
NULL
);
...
@@ -368,18 +401,15 @@ int main(int argc, char **argv) {
...
@@ -368,18 +401,15 @@ int main(int argc, char **argv) {
TestWithPCInsideNonInlineFunction
();
TestWithPCInsideNonInlineFunction
();
TestWithReturnAddress
();
TestWithReturnAddress
();
return
RUN_ALL_TESTS
();
return
RUN_ALL_TESTS
();
#else
# elif defined(OS_WINDOWS)
return
0
;
TestWithReturnAddress
();
#endif
return
RUN_ALL_TESTS
();
}
# else // OS_WINDOWS
#else
int
main
()
{
#ifdef HAVE_SYMBOLIZE
printf
(
"PASS (no symbolize_unittest support)
\n
"
);
printf
(
"PASS (no symbolize_unittest support)
\n
"
);
return
0
;
# endif // __ELF__
#else
#else
printf
(
"PASS (no symbolize support)
\n
"
);
printf
(
"PASS (no symbolize support)
\n
"
);
#endif
return
0
;
return
0
;
#endif // HAVE_SYMBOLIZE
}
}
#endif // HAVE_STACKTRACE
src/utilities.cc
View file @
5cfa9a28
...
@@ -137,17 +137,19 @@ static void DumpStackTraceAndExit() {
...
@@ -137,17 +137,19 @@ static void DumpStackTraceAndExit() {
DumpStackTrace
(
1
,
DebugWriteToStderr
,
NULL
);
DumpStackTrace
(
1
,
DebugWriteToStderr
,
NULL
);
// TOOD(hamaji): Use signal instead of sigaction?
// TOOD(hamaji): Use signal instead of sigaction?
#ifdef HAVE_SIGACTION
if
(
IsFailureSignalHandlerInstalled
())
{
if
(
IsFailureSignalHandlerInstalled
())
{
// Set the default signal handler for SIGABRT, to avoid invoking our
// Set the default signal handler for SIGABRT, to avoid invoking our
// own signal handler installed by InstallFailureSignalHandler().
// own signal handler installed by InstallFailureSignalHandler().
#ifdef HAVE_SIGACTION
struct
sigaction
sig_action
;
struct
sigaction
sig_action
;
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
memset
(
&
sig_action
,
0
,
sizeof
(
sig_action
));
sigemptyset
(
&
sig_action
.
sa_mask
);
sigemptyset
(
&
sig_action
.
sa_mask
);
sig_action
.
sa_handler
=
SIG_DFL
;
sig_action
.
sa_handler
=
SIG_DFL
;
sigaction
(
SIGABRT
,
&
sig_action
,
NULL
);
sigaction
(
SIGABRT
,
&
sig_action
,
NULL
);
}
#elif defined(OS_WINDOWS)
signal
(
SIGABRT
,
SIG_DFL
);
#endif // HAVE_SIGACTION
#endif // HAVE_SIGACTION
}
abort
();
abort
();
}
}
...
...
src/utilities.h
View file @
5cfa9a28
...
@@ -99,6 +99,8 @@
...
@@ -99,6 +99,8 @@
// malloc() from the unwinder. This is a problem because we're
// malloc() from the unwinder. This is a problem because we're
// trying to use the unwinder to instrument malloc().
// trying to use the unwinder to instrument malloc().
//
//
// 4) The Windows API CaptureStackTrace.
//
// Note: if you add a new implementation here, make sure it works
// Note: if you add a new implementation here, make sure it works
// correctly when GetStackTrace() is called with max_depth == 0.
// correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that.
// Some code may do that.
...
@@ -112,6 +114,8 @@
...
@@ -112,6 +114,8 @@
# define STACKTRACE_H "stacktrace_x86_64-inl.h"
# define STACKTRACE_H "stacktrace_x86_64-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# elif defined(OS_WINDOWS)
# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif
# endif
#endif
#endif
...
@@ -129,6 +133,9 @@
...
@@ -129,6 +133,9 @@
#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
# define HAVE_SYMBOLIZE
#elif defined(OS_WINDOWS)
// Use DbgHelp to symbolize
# define HAVE_SYMBOLIZE
#endif
#endif
#ifndef ARRAYSIZE
#ifndef ARRAYSIZE
...
@@ -143,6 +150,9 @@ namespace glog_internal_namespace_ {
...
@@ -143,6 +150,9 @@ namespace glog_internal_namespace_ {
#ifdef HAVE___ATTRIBUTE__
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
# define HAVE_ATTRIBUTE_NOINLINE
#elif defined(OS_WINDOWS)
# define ATTRIBUTE_NOINLINE __declspec(noinline)
# define HAVE_ATTRIBUTE_NOINLINE
#else
#else
# define ATTRIBUTE_NOINLINE
# define ATTRIBUTE_NOINLINE
#endif
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment