Add some data annotation to allow for data profiling
[hiphop-php.git] / hphp / runtime / vm / debug / debug.cpp
blobae5ac52e7880eae33a5a475f286a1a9db3a42d35
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <cxxabi.h>
31 #include <bfd.h>
33 using namespace HPHP::JIT;
35 namespace HPHP {
36 namespace Debug {
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,
47 sizeof m_perfMapName,
48 "/tmp/perf-%d.map", getpid());
49 if (RuntimeOption::EvalPerfPidMap) {
50 m_perfMap = fopen(m_perfMapName, "w");
52 snprintf(m_dataMapName,
53 sizeof 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() {
62 if (m_perfMap) {
63 fclose(m_perfMap);
64 if (!RuntimeOption::EvalKeepPerfPidMap) {
65 unlink(m_perfMapName);
69 if (m_dataMap) {
70 fclose(m_dataMap);
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);
82 #ifdef BFD_DECOMPRESS
83 abfd->flags |= BFD_DECOMPRESS;
84 #endif
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];
100 if (sym->flags &
101 (BSF_INDIRECT |
102 BSF_SECTION_SYM |
103 BSF_FILE |
104 BSF_DEBUGGING_RELOC |
105 BSF_OBJECT)) {
106 continue;
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)) {
113 continue;
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;
129 int status;
130 char* demangled =
131 abi::__cxa_demangle(sym->name, nullptr, nullptr, &status);
132 if (status != 0) demangled = const_cast<char*>(sym->name);
133 unsigned size;
134 if (i + 1 < sorted.size()) {
135 auto s2 = sorted[i + 1];
136 size = s2->section->vma + s2->value - addr;
137 } else {
138 size = uintptr_t(pidMapOverlayEnd) - addr;
140 if (!size) continue;
141 fprintf(m_perfMap, "%lx %x %s\n",
142 long(addr), size, demangled);
143 if (status == 0) free(demangled);
146 free(symbol_table);
147 free(match);
149 bfd_close(abfd);
150 return;
153 void DebugInfo::recordStub(TCRange range, const char* name) {
154 if (range.isAstubs()) {
155 m_astubsDwarfInfo.addTracelet(range, name, nullptr, nullptr, false, false);
156 } else {
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()),
168 range.size(),
169 name.c_str());
170 fflush(m_perfMap);
173 void DebugInfo::recordBCInstr(TCRange range, uint32_t op) {
174 static const char* opcodeName[] = {
175 #define O(name, imm, push, pop, flags) \
176 #name,
177 OPCODES
178 #undef O
181 static const char* astubOpcodeName[] = {
182 "OpAstubStart",
183 #define O(name, imm, push, pop, flags) \
184 #name "-Astub",
185 OPCODES
186 #undef O
189 static const char* highOpcodeName[] = {
190 "OpHighStart",
191 #define O(name) \
192 #name,
193 HIGH_OPCODES
194 #undef O
198 if (RuntimeOption::EvalProfileBC) {
199 if (!m_perfMap) return;
200 const char* name;
201 if (op < Op_count) {
202 name = opcodeName[op];
203 } else if (op < OpAstubCount) {
204 name = astubOpcodeName[op - OpAstubStart];
205 } else {
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);
218 } else {
219 m_aDwarfInfo.addTracelet(range, nullptr, func, instr, exit, inPrologue);
223 void DebugInfo::recordDataMap(void* from, void* to, const std::string& desc) {
224 if (!mcg) return;
225 return Get()->recordDataMapImpl(from, to, desc);
228 void DebugInfo::recordDataMapImpl(void* from, void* to,
229 const std::string& desc) {
230 if (m_dataMap) {
231 fprintf(m_dataMap, "%" PRIxPTR " %" PRIx64 " %s\n",
232 uintptr_t(from),
233 uint64_t((char*)to - (char*)from),
234 desc.c_str());
235 fflush(m_dataMap);
239 void DebugInfo::debugSync() {
240 m_aDwarfInfo.syncChunks();
241 m_astubsDwarfInfo.syncChunks();
244 std::string lookupFunction(const Func* f,
245 bool exit,
246 bool inPrologue,
247 bool pseudoWithFileName) {
248 // TODO: mangle the namespace and name?
249 std::string fname("PHP::");
250 if (pseudoWithFileName) {
251 fname += f->unit()->filepath()->data();
252 fname += "::";
254 if (!strcmp(f->name()->data(), "")) {
255 if (!exit) {
256 fname += "__pseudoMain";
257 } else {
258 fname += "__exit";
260 return fname;
262 fname += f->fullName()->data();
263 if (inPrologue)
264 fname += "$prologue";
265 return fname;