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/runtime/vm/debug/dwarf.h"
20 #include "hphp/runtime/vm/debug/gdb-jit.h"
22 #include "hphp/runtime/base/execution-context.h"
23 #include "hphp/runtime/vm/jit/translator.h"
24 #include "hphp/runtime/vm/jit/translator-inline.h"
26 #if (!defined(__APPLE__) && !defined(__FreeBSD__) && \
27 !defined(__CYGWIN__) && !defined(_MSC_VER))
28 #include "hphp/runtime/vm/debug/elfwriter.h"
29 #define USE_ELF_WRITER 1
32 using namespace HPHP::jit
;
38 LIBDWARF_CALLBACK_NAME_TYPE name
, int size
, Dwarf_Unsigned type
,
39 Dwarf_Unsigned flags
, Dwarf_Unsigned link
, Dwarf_Unsigned info
,
40 Dwarf_Unsigned
*sect_name_index
, Dwarf_Ptr handle
, int *error
) {
42 ElfWriter
*e
= reinterpret_cast<ElfWriter
*>(handle
);
43 return e
->dwarfCallback(name
, size
, type
, flags
, link
, info
);
49 void DwarfBuf::byte(uint8_t c
) {
53 void DwarfBuf::clear() {
57 int DwarfBuf::size() {
61 uint8_t *DwarfBuf::getBuf() {
65 void DwarfBuf::print() {
67 for (i
= 0; i
< m_buf
.size(); i
++)
68 printf("%x ", m_buf
[i
]);
72 void DwarfBuf::dwarf_cfa_def_cfa(uint8_t reg
, uint8_t offset
) {
78 void DwarfBuf::dwarf_cfa_same_value(uint8_t reg
) {
79 byte(DW_CFA_same_value
);
83 void DwarfBuf::dwarf_cfa_offset_extended_sf(uint8_t reg
, int8_t offset
) {
84 byte(DW_CFA_offset_extended_sf
);
89 const char *DwarfInfo::lookupFile(const Unit
*unit
) {
90 const char *file
= nullptr;
91 if (unit
&& unit
->filepath()) {
92 file
= unit
->filepath()->data();
94 if (file
== nullptr || strlen(file
) == 0) {
100 void DwarfInfo::addLineEntries(TCRange range
,
104 if (unit
== nullptr || instr
== nullptr) {
105 // For stubs, just add line 0
106 f
->m_lineTable
.push_back(LineEntry(range
, 0));
109 Offset offset
= unit
->offsetOf(instr
);
111 int lineNum
= unit
->getLineNumber(offset
);
113 f
->m_lineTable
.push_back(LineEntry(range
, lineNum
));
117 void DwarfInfo::transferFuncs(DwarfChunk
* from
, DwarfChunk
* to
) {
118 unsigned int size
= from
->m_functions
.size();
119 for (unsigned int i
= 0; i
< size
; i
++) {
120 FunctionInfo
* f
= from
->m_functions
[i
];
122 to
->m_functions
.push_back(f
);
126 void DwarfInfo::compactChunks() {
128 for (i
= 1; i
< m_dwarfChunks
.size(); i
++) {
129 if (m_dwarfChunks
[i
] == nullptr) {
133 if (i
>= m_dwarfChunks
.size()) {
134 m_dwarfChunks
.push_back(nullptr);
136 DwarfChunk
* chunk
= new DwarfChunk();
137 for (j
= 0; j
< i
; j
++) {
138 transferFuncs(m_dwarfChunks
[j
], chunk
);
139 // unregister chunk from gdb and free chunk
140 unregister_gdb_chunk(m_dwarfChunks
[j
]);
141 delete(m_dwarfChunks
[j
]);
142 m_dwarfChunks
[j
] = nullptr;
144 m_dwarfChunks
[i
] = chunk
;
145 #ifdef USE_ELF_WRITER
146 // register compacted chunk with gdb
147 ElfWriter e
= ElfWriter(chunk
);
151 static Mutex
s_lock(RankLeaf
);
153 DwarfChunk
* DwarfInfo::addTracelet(TCRange range
,
154 folly::Optional
<std::string
> name
,
159 DwarfChunk
* chunk
= nullptr;
160 FunctionInfo
* f
= new FunctionInfo(range
, exit
);
161 const Unit
* unit
= func
? func
->unit(): nullptr;
165 assert(func
!= nullptr);
166 f
->name
= lookupFunction(func
, exit
, inPrologue
, true);
167 auto names
= func
->localNames();
168 for (int i
= 0; i
< func
->numNamedLocals(); i
++) {
169 f
->m_namedLocals
.push_back(names
[i
]->toCppString());
172 f
->file
= lookupFile(unit
);
174 TCA start
= range
.begin();
175 const TCA end
= range
.end();
178 auto const it
= m_functions
.lower_bound(range
.begin());
179 auto const fi
= it
->second
;
180 if (it
!= m_functions
.end() && fi
->name
== f
->name
&&
181 fi
->file
== f
->file
&&
182 start
> fi
->range
.begin() &&
183 end
> fi
->range
.end()) {
184 // XXX: verify that overlapping address come from jmp fixups
185 start
= fi
->range
.end();
186 fi
->range
.extend(end
);
187 m_functions
[end
] = fi
;
188 m_functions
.erase(it
);
190 f
= m_functions
[end
];
191 assert(f
->m_chunk
!= nullptr);
192 f
->m_chunk
->clearSynced();
193 f
->clearPerfSynced();
195 m_functions
[end
] = f
;
198 addLineEntries(TCRange(start
, end
, range
.isAcold()), unit
, instr
, f
);
200 if (f
->m_chunk
== nullptr) {
201 if (m_dwarfChunks
.size() == 0 || m_dwarfChunks
[0] == nullptr) {
202 // new chunk of base size
203 chunk
= new DwarfChunk();
204 m_dwarfChunks
.push_back(chunk
);
205 } else if (m_dwarfChunks
[0]->m_functions
.size()
206 < RuntimeOption::EvalGdbSyncChunks
) {
208 chunk
= m_dwarfChunks
[0];
209 chunk
->clearSynced();
213 m_dwarfChunks
[0] = chunk
= new DwarfChunk();
215 chunk
->m_functions
.push_back(f
);
219 #ifdef USE_ELF_WRITER
220 if (f
->m_chunk
->m_functions
.size() >= RuntimeOption::EvalGdbSyncChunks
) {
221 ElfWriter e
= ElfWriter(f
->m_chunk
);
228 void DwarfInfo::syncChunks() {
231 for (i
= 0; i
< m_dwarfChunks
.size(); i
++) {
232 if (m_dwarfChunks
[i
] && !m_dwarfChunks
[i
]->isSynced()) {
233 unregister_gdb_chunk(m_dwarfChunks
[i
]);
234 #ifdef USE_ELF_WRITER
235 ElfWriter e
= ElfWriter(m_dwarfChunks
[i
]);