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
f1d64f7d
Commit
f1d64f7d
authored
Mar 04, 2017
by
Andrew Schwartzmeyer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support symbolizer and demangler on Windows
parent
e5d36443
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
181 additions
and
71 deletions
+181
-71
CMakeLists.txt
CMakeLists.txt
+1
-0
demangle.cc
src/demangle.cc
+31
-0
demangle_unittest.cc
src/demangle_unittest.cc
+31
-10
stacktrace_windows-inl.h
src/stacktrace_windows-inl.h
+3
-39
symbolize.cc
src/symbolize.cc
+60
-0
symbolize_unittest.cc
src/symbolize_unittest.cc
+52
-22
utilities.h
src/utilities.h
+3
-0
No files found.
CMakeLists.txt
View file @
f1d64f7d
...
...
@@ -457,6 +457,7 @@ endif (HAVE_EXECINFO_H)
if
(
WIN32
)
set
(
HAVE_STACKTRACE 1
)
set
(
HAVE_SYMBOLIZE 1
)
target_link_libraries
(
glog PUBLIC Dbghelp.lib
)
endif
(
WIN32
)
...
...
src/demangle.cc
View file @
f1d64f7d
...
...
@@ -35,10 +35,16 @@
// 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>
#endif
_START_GOOGLE_NAMESPACE_
#if !defined(OS_WINDOWS)
typedef
struct
{
const
char
*
abbrev
;
const
char
*
real_name
;
...
...
@@ -1293,12 +1299,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_
src/demangle_unittest.cc
View file @
f1d64f7d
...
...
@@ -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
...
...
@@ -123,6 +142,8 @@ TEST(Demangle, FromFile) {
}
}
#endif
int
main
(
int
argc
,
char
**
argv
)
{
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
...
...
src/stacktrace_windows-inl.h
View file @
f1d64f7d
...
...
@@ -33,54 +33,18 @@
#include "port.h"
#include "stacktrace.h"
#include "Dbghelp.h"
#include <vector>
#include <DbgHelp.h>
_START_GOOGLE_NAMESPACE_
static
bool
ready_to_run
=
false
;
class
StackTraceInit
{
public
:
HANDLE
hProcess
;
StackTraceInit
()
{
// Initialize the symbol handler
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
hProcess
=
GetCurrentProcess
();
SymSetOptions
(
SYMOPT_UNDNAME
|
SYMOPT_DEFERRED_LOADS
);
SymInitialize
(
hProcess
,
NULL
,
true
);
ready_to_run
=
true
;
}
~
StackTraceInit
()
{
SymCleanup
(
hProcess
);
ready_to_run
=
false
;
}
};
static
const
StackTraceInit
module_initializer
;
// Force initialization
// If you change this function, also change GetStackFrames below.
int
GetStackTrace
(
void
**
result
,
int
max_depth
,
int
skip_count
)
{
if
(
!
ready_to_run
)
{
return
0
;
}
skip_count
++
;
// we want to skip the current frame as well
if
(
max_depth
>
64
)
{
max_depth
=
64
;
}
s
td
::
vector
<
void
*>
stack
(
max_depth
);
s
kip_count
++
;
// we want to skip the current frame as well
// This API is thread-safe (moreover it walks only the current thread).
int
size
=
CaptureStackBackTrace
(
skip_count
,
max_depth
,
&
stack
[
0
],
NULL
);
for
(
int
i
=
0
;
i
<
size
;
++
i
)
{
// Resolve symbol information from address.
char
buffer
[
sizeof
(
SYMBOL_INFO
)
+
MAX_SYM_NAME
*
sizeof
(
TCHAR
)];
SYMBOL_INFO
*
symbol
=
reinterpret_cast
<
SYMBOL_INFO
*>
(
buffer
);
symbol
->
SizeOfStruct
=
sizeof
(
SYMBOL_INFO
);
symbol
->
MaxNameLen
=
MAX_SYM_NAME
;
SymFromAddr
(
module_initializer
.
hProcess
,
reinterpret_cast
<
DWORD64
>
(
stack
[
i
]),
0
,
symbol
);
result
[
i
]
=
stack
[
i
];
}
return
size
;
return
CaptureStackBackTrace
(
skip_count
,
max_depth
,
result
,
NULL
);
}
_END_GOOGLE_NAMESPACE_
src/symbolize.cc
View file @
f1d64f7d
...
...
@@ -837,6 +837,66 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
_END_GOOGLE_NAMESPACE_
#elif defined(OS_WINDOWS)
#include <DbgHelp.h>
_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
# error BUG: HAVE_SYMBOLIZE was wrongly set
#endif
...
...
src/symbolize_unittest.cc
View file @
f1d64f7d
...
...
@@ -49,10 +49,22 @@ using namespace GFLAGS_NAMESPACE;
using
namespace
std
;
using
namespace
GOOGLE_NAMESPACE
;
#if defined(HAVE_STACKTRACE)
&& defined(__ELF__)
#if defined(HAVE_STACKTRACE)
#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.
// Uses lots of GCC specific features.
#if defined(__GNUC__) && !defined(__OPENCC__)
...
...
@@ -70,16 +82,6 @@ using namespace GOOGLE_NAMESPACE;
# endif // defined(__i386__) || defined(__x86_64__)
#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.
extern
"C"
{
void
nonstatic_func
()
{
...
...
@@ -355,11 +357,42 @@ void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#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
)
{
FLAGS_logtostderr
=
true
;
InitGoogleLogging
(
argv
[
0
]);
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
// used to install some callback function at InitGoogle() time.
InstallSymbolizeCallback
(
NULL
);
...
...
@@ -368,18 +401,15 @@ int main(int argc, char **argv) {
TestWithPCInsideNonInlineFunction
();
TestWithReturnAddress
();
return
RUN_ALL_TESTS
();
#else
return
0
;
#endif
}
#else
int
main
()
{
#ifdef HAVE_SYMBOLIZE
# elif defined(OS_WINDOWS)
TestWithReturnAddress
();
return
RUN_ALL_TESTS
();
# else // OS_WINDOWS
printf
(
"PASS (no symbolize_unittest support)
\n
"
);
return
0
;
# endif // __ELF__
#else
printf
(
"PASS (no symbolize support)
\n
"
);
#endif
return
0
;
#endif // HAVE_SYMBOLIZE
}
#endif // HAVE_STACKTRACE
src/utilities.h
View file @
f1d64f7d
...
...
@@ -133,6 +133,9 @@
#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
#elif defined(OS_WINDOWS)
// Use DbgHelp to symbolize
# define HAVE_SYMBOLIZE
#endif
#ifndef ARRAYSIZE
...
...
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