2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/debug/debug.h"
18 #include "hphp/runtime/vm/debug/gdb-jit.h"
19 #include "hphp/runtime/vm/jit/mc-generator.h"
21 #include "hphp/runtime/base/execution-context.h"
23 #include "hphp/util/current-executable.h"
25 #include <sys/types.h>
33 using namespace HPHP::JIT
;
38 void* DebugInfo::pidMapOverlayStart
;
39 void* DebugInfo::pidMapOverlayEnd
;
41 DebugInfo
* DebugInfo::Get() {
42 return mcg
->getDebugInfo();
45 DebugInfo::DebugInfo() : m_perfMap(0), m_dataMap(0) {
46 snprintf(m_perfMapName
,
48 "/tmp/perf-%d.map", getpid());
49 if (RuntimeOption::EvalPerfPidMap
) {
50 m_perfMap
= fopen(m_perfMapName
, "w");
52 snprintf(m_dataMapName
,
54 "/tmp/perf-data-%d.map", getpid());
55 if (RuntimeOption::EvalPerfDataMap
) {
56 m_dataMap
= fopen(m_dataMapName
, "w");
58 generatePidMapOverlay();
61 DebugInfo::~DebugInfo() {
64 if (!RuntimeOption::EvalKeepPerfPidMap
) {
65 unlink(m_perfMapName
);
71 if (!RuntimeOption::EvalKeepPerfPidMap
) {
72 unlink(m_dataMapName
);
77 void DebugInfo::generatePidMapOverlay() {
78 if (!m_perfMap
|| !pidMapOverlayStart
) return;
80 std::string self
= current_executable_path();
81 bfd
* abfd
= bfd_openr(self
.c_str(), nullptr);
83 abfd
->flags
|= BFD_DECOMPRESS
;
85 char **match
= nullptr;
86 if (!bfd_check_format(abfd
, bfd_archive
) &&
87 bfd_check_format_matches(abfd
, bfd_object
, &match
)) {
89 std::vector
<asymbol
*> sorted
;
90 long storage_needed
= bfd_get_symtab_upper_bound (abfd
);
92 if (storage_needed
<= 0) return;
94 auto symbol_table
= (asymbol
**)malloc(storage_needed
);
96 long number_of_symbols
= bfd_canonicalize_symtab(abfd
, symbol_table
);
98 for (long i
= 0; i
< number_of_symbols
; i
++) {
99 auto sym
= symbol_table
[i
];
104 BSF_DEBUGGING_RELOC
|
108 auto sec
= sym
->section
;
109 if (!(sec
->flags
& (SEC_ALLOC
|SEC_LOAD
|SEC_CODE
))) continue;
110 auto addr
= sec
->vma
+ sym
->value
;
111 if (addr
< uintptr_t(pidMapOverlayStart
) ||
112 addr
>= uintptr_t(pidMapOverlayEnd
)) {
115 sorted
.push_back(sym
);
118 std::sort(sorted
.begin(), sorted
.end(), [](asymbol
* a
, asymbol
* b
) {
119 auto addra
= a
->section
->vma
+ a
->value
;
120 auto addrb
= b
->section
->vma
+ b
->value
;
121 if (addra
!= addrb
) return addra
< addrb
;
122 return strncmp("_ZN4HPHP", a
->name
, 8) &&
123 !strncmp("_ZN4HPHP", b
->name
, 8);
126 for (size_t i
= 0; i
< sorted
.size(); i
++) {
127 auto sym
= sorted
[i
];
128 auto addr
= sym
->section
->vma
+ sym
->value
;
131 abi::__cxa_demangle(sym
->name
, nullptr, nullptr, &status
);
132 if (status
!= 0) demangled
= const_cast<char*>(sym
->name
);
134 if (i
+ 1 < sorted
.size()) {
135 auto s2
= sorted
[i
+ 1];
136 size
= s2
->section
->vma
+ s2
->value
- addr
;
138 size
= uintptr_t(pidMapOverlayEnd
) - addr
;
141 fprintf(m_perfMap
, "%lx %x %s\n",
142 long(addr
), size
, demangled
);
143 if (status
== 0) free(demangled
);
153 void DebugInfo::recordStub(TCRange range
, const char* name
) {
154 if (range
.isAstubs()) {
155 m_astubsDwarfInfo
.addTracelet(range
, name
, nullptr, nullptr, false, false);
157 m_aDwarfInfo
.addTracelet(range
, name
, nullptr, nullptr, false, false);
161 void DebugInfo::recordPerfMap(TCRange range
, const Func
* func
,
162 bool exit
, bool inPrologue
) {
163 if (!m_perfMap
) return;
164 if (RuntimeOption::EvalProfileBC
) return;
165 std::string name
= lookupFunction(func
, exit
, inPrologue
, true);
166 fprintf(m_perfMap
, "%lx %x %s\n",
167 reinterpret_cast<uintptr_t>(range
.begin()),
173 void DebugInfo::recordBCInstr(TCRange range
, uint32_t op
) {
174 static const char* opcodeName
[] = {
175 #define O(name, imm, push, pop, flags) \
181 static const char* astubOpcodeName
[] = {
183 #define O(name, imm, push, pop, flags) \
189 static const char* highOpcodeName
[] = {
198 if (RuntimeOption::EvalProfileBC
) {
199 if (!m_perfMap
) return;
202 name
= opcodeName
[op
];
203 } else if (op
< OpAstubCount
) {
204 name
= astubOpcodeName
[op
- OpAstubStart
];
206 name
= highOpcodeName
[op
- OpHighStart
];
208 fprintf(m_perfMap
, "%lx %x %s\n",
209 uintptr_t(range
.begin()), range
.size(), name
);
213 void DebugInfo::recordTracelet(TCRange range
, const Func
* func
,
214 const Op
* instr
, bool exit
, bool inPrologue
) {
215 if (range
.isAstubs()) {
216 m_astubsDwarfInfo
.addTracelet(range
, nullptr, func
,
217 instr
, exit
, inPrologue
);
219 m_aDwarfInfo
.addTracelet(range
, nullptr, func
, instr
, exit
, inPrologue
);
223 void DebugInfo::recordDataMap(void* from
, void* to
, const std::string
& desc
) {
225 return Get()->recordDataMapImpl(from
, to
, desc
);
228 void DebugInfo::recordDataMapImpl(void* from
, void* to
,
229 const std::string
& desc
) {
231 fprintf(m_dataMap
, "%" PRIxPTR
" %" PRIx64
" %s\n",
233 uint64_t((char*)to
- (char*)from
),
239 void DebugInfo::debugSync() {
240 m_aDwarfInfo
.syncChunks();
241 m_astubsDwarfInfo
.syncChunks();
244 std::string
lookupFunction(const Func
* f
,
247 bool pseudoWithFileName
) {
248 // TODO: mangle the namespace and name?
249 std::string
fname("PHP::");
250 if (pseudoWithFileName
) {
251 fname
+= f
->unit()->filepath()->data();
254 if (!strcmp(f
->name()->data(), "")) {
256 fname
+= "__pseudoMain";
262 fname
+= f
->fullName()->data();
264 fname
+= "$prologue";