codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / util / abi-cxx.cpp
blobe6f960532f2b2bf97714bcc1b31fb66108372924
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <memory>
23 #include <mutex>
24 #include <string>
25 #include <unordered_map>
27 #if (defined(__CYGWIN__) || defined(__MINGW__) || defined(_MSC_VER))
28 # include <windows.h>
29 # include <dbghelp.h>
30 # ifndef _MSC_VER
31 # include <cxxabi.h>
32 # endif
33 #else
34 # include <cxxabi.h>
35 # include <execinfo.h>
36 #endif
38 #include <folly/Format.h>
40 #include "hphp/util/functional.h"
41 #include "hphp/util/compatibility.h"
43 #ifdef FACEBOOK
44 #include <folly/experimental/symbolizer/Symbolizer.h>
45 #endif
47 namespace HPHP {
49 //////////////////////////////////////////////////////////////////////
51 namespace {
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) {
63 G g(nameCacheLock);
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();
71 SYMBOL_INFO *symbol;
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);
84 int status;
85 #ifdef _MSC_VER
86 char* demangledName = (char*)calloc(1024, sizeof(char));
87 status = !(int)UnDecorateSymbolName(symbol->Name, demangledName, 1023, UNDNAME_COMPLETE);
88 #else
89 char* demangledName = abi::__cxa_demangle(functionName.c_str(),
90 0, 0, &status);
91 #endif
92 SCOPE_EXIT { free(demangledName); };
93 if (status == 0) functionName.assign(demangledName);
96 free(symbol);
98 SymCleanup(process);
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();
107 #else
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, '(');
128 if (start) {
129 start++;
130 char* end = strchr(start, '+');
131 if (end != nullptr) {
132 functionName.assign(start, end);
133 int status;
134 char* demangledName = abi::__cxa_demangle(functionName.c_str(),
135 0, 0, &status);
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.
144 free(symbols);
145 #endif
147 if (functionName.empty()) functionName = folly::format("{}", codeAddr).str();
149 G g(nameCacheLock);
150 return nameCache[codeAddr] = functionName;
153 //////////////////////////////////////////////////////////////////////