2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/abi-cxx.h"
25 #include <unordered_map>
27 #if (defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER))
35 # include <execinfo.h>
38 #include <folly/Format.h>
40 #include "hphp/util/functional.h"
41 #include "hphp/util/compatibility.h"
44 #include <folly/experimental/symbolizer/Symbolizer.h>
49 //////////////////////////////////////////////////////////////////////
53 typedef std::lock_guard
<std::mutex
> G
;
54 std::mutex nameCacheLock
;
55 std::unordered_map
<void*, std::string
, pointer_hash
<void>> nameCache
;
59 //////////////////////////////////////////////////////////////////////
61 std::string
getNativeFunctionName(void* codeAddr
) {
64 auto it
= nameCache
.find(codeAddr
);
65 if (it
!= end(nameCache
)) return it
->second
;
67 std::string functionName
;
69 #if defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER)
70 HANDLE process
= GetCurrentProcess();
72 DWORD64 addr_disp
= 0;
74 // syminitialize and symcleanup should really be once per process
75 SymInitialize(process
, nullptr, TRUE
);
77 symbol
= (SYMBOL_INFO
*)calloc(sizeof(SYMBOL_INFO
) + 256 * sizeof(char), 1);
78 symbol
->MaxNameLen
= 255;
79 symbol
->SizeOfStruct
= sizeof(SYMBOL_INFO
);
81 if(SymFromAddr(process
, (DWORD64
) codeAddr
, &addr_disp
, symbol
)) {
82 functionName
.assign(symbol
->Name
);
86 char* demangledName
= (char*)calloc(1024, sizeof(char));
87 status
= !(int)UnDecorateSymbolName(symbol
->Name
, demangledName
, 1023, UNDNAME_COMPLETE
);
89 char* demangledName
= abi::__cxa_demangle(functionName
.c_str(),
92 SCOPE_EXIT
{ free(demangledName
); };
93 if (status
== 0) functionName
.assign(demangledName
);
99 #elif defined(FACEBOOK)
101 folly::symbolizer::Symbolizer symbolizer
;
102 folly::symbolizer::SymbolizedFrame frame
;
103 if (symbolizer
.symbolize(uintptr_t(codeAddr
), frame
)) {
104 functionName
= frame
.demangledName().toStdString();
108 void* buf
[1] = {codeAddr
};
109 char** symbols
= backtrace_symbols(buf
, 1);
111 if (symbols
!= nullptr) {
113 // the output from backtrace_symbols looks like this:
114 // ../path/hhvm/hhvm(_ZN4HPHP2VM6Transl17interpOneIterInitEv+0) [0x17cebe9]
116 // we first want to extract the mangled name from it to get this:
117 // _ZN4HPHP2VM6Transl17interpOneIterInitEv
119 // and then pass this to abi::__cxa_demangle to get the demanged name:
120 // HPHP::jit::interpOneIterInit()
122 // Sometimes, though, backtrace_symbols can't find the function name
123 // and ends up giving us a blank managled name, like this:
124 // ../path/hhvm/hhvm() [0x17e4d01]
125 // or this: [0x7fffca800130]
127 char* start
= strchr(*symbols
, '(');
130 char* end
= strchr(start
, '+');
131 if (end
!= nullptr) {
132 functionName
.assign(start
, end
);
134 char* demangledName
= abi::__cxa_demangle(functionName
.c_str(),
136 SCOPE_EXIT
{ free(demangledName
); };
137 if (status
== 0) functionName
.assign(demangledName
);
142 // backtrace_symbols requires that we free the array of strings but not the
143 // strings themselves.
147 if (functionName
.empty()) functionName
= folly::format("{}", codeAddr
).str();
150 return nameCache
[codeAddr
] = functionName
;
153 //////////////////////////////////////////////////////////////////////