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
8 years ago
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
)
...
...
This diff is collapsed.
Click to expand it.
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_
This diff is collapsed.
Click to expand it.
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
);
...
...
This diff is collapsed.
Click to expand it.
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_
This diff is collapsed.
Click to expand it.
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
...
...
This diff is collapsed.
Click to expand it.
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
This diff is collapsed.
Click to expand it.
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
...
...
This diff is collapsed.
Click to expand it.
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