cf197fee81
Facebook: ~bsimmers/bin/move-vm-files.sh
305 linhas
8.0 KiB
C++
305 linhas
8.0 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
#include <stdio.h>
|
|
#include "hphp/runtime/vm/debug/dwarf.h"
|
|
#include "debug.h"
|
|
#include "hphp/runtime/vm/debug/elfwriter.h"
|
|
#include "hphp/runtime/vm/debug/gdb-jit.h"
|
|
|
|
#include "hphp/runtime/base/types.h"
|
|
#include "hphp/runtime/base/execution_context.h"
|
|
#include "hphp/runtime/vm/jit/translator.h"
|
|
#include "hphp/runtime/vm/jit/translator-inline.h"
|
|
|
|
using namespace HPHP::Transl;
|
|
|
|
namespace HPHP {
|
|
namespace Debug {
|
|
|
|
|
|
int g_dwarfCallback(char *name, int size, Dwarf_Unsigned type,
|
|
Dwarf_Unsigned flags, Dwarf_Unsigned link, Dwarf_Unsigned info,
|
|
Dwarf_Unsigned *sect_name_index, Dwarf_Ptr handle, int *error) {
|
|
ElfWriter *e = reinterpret_cast<ElfWriter *>(handle);
|
|
return e->dwarfCallback(name, size, type, flags, link, info);
|
|
}
|
|
|
|
void DwarfBuf::byte(uint8_t c) {
|
|
m_buf.push_back(c);
|
|
}
|
|
|
|
void DwarfBuf::byte(int off, uint8_t c) {
|
|
assert((size_t)off < m_buf.size());
|
|
m_buf[off] = c;
|
|
}
|
|
|
|
void DwarfBuf::word(uint16_t w) {
|
|
byte(w & 0xff);
|
|
byte((w >> 8) & 0xff);
|
|
}
|
|
|
|
void DwarfBuf::word(int off, uint16_t w) {
|
|
byte(off, (w & 0xff));
|
|
byte(off + 1, ((w >> 8) & 0xff));
|
|
}
|
|
|
|
void DwarfBuf::dword(uint32_t d) {
|
|
word(d & 0xffff);
|
|
word((d >> 16) & 0xffff);
|
|
}
|
|
|
|
void DwarfBuf::dword(int off, uint32_t d) {
|
|
word(off, (d & 0xffff));
|
|
word(off + 2, ((d >> 16) & 0xffff));
|
|
}
|
|
|
|
void DwarfBuf::qword(uint64_t q) {
|
|
dword(q & 0xffffffff);
|
|
dword((q >> 32) & 0xfffffffff);
|
|
}
|
|
|
|
void DwarfBuf::clear() {
|
|
m_buf.clear();
|
|
}
|
|
|
|
int DwarfBuf::size() {
|
|
return m_buf.size();
|
|
}
|
|
|
|
uint8_t *DwarfBuf::getBuf() {
|
|
return &m_buf[0];
|
|
}
|
|
|
|
void DwarfBuf::print() {
|
|
unsigned int i;
|
|
for (i = 0; i < m_buf.size(); i++)
|
|
printf("%x ", m_buf[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
void DwarfBuf::dwarf_op_const4s(int x) {
|
|
byte(DW_OP_const4s);
|
|
dword(x);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_op_deref_size(uint8_t size) {
|
|
byte(DW_OP_deref_size);
|
|
byte(size);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_sfp_expr(int offset, int scale) {
|
|
byte(DW_OP_dup);
|
|
dwarf_op_const4s(offset);
|
|
byte(DW_OP_plus);
|
|
dwarf_op_deref_size(sizeof(uint32_t));
|
|
dwarf_op_const4s(scale);
|
|
byte(DW_OP_mul);
|
|
byte(DW_OP_plus);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_sfp(uint8_t reg, int offset, int scale) {
|
|
DwarfBuf b;
|
|
byte(DW_CFA_val_expression);
|
|
byte(reg);
|
|
b.dwarf_sfp_expr(offset, scale);
|
|
/* this assumes expression fits in 127 bytes, else we have
|
|
to LEB128 encode size */
|
|
byte(b.size());
|
|
dwarf_sfp_expr(offset, scale);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_unwind_rsp() {
|
|
byte(DW_CFA_val_expression);
|
|
byte(RSP);
|
|
/* instruction sequence of length 2 */
|
|
byte(2);
|
|
/* add 8 to RSP (reg 7) */
|
|
byte(DW_OP_breg7);
|
|
byte(8);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_same_value(uint8_t reg) {
|
|
byte(DW_CFA_same_value);
|
|
byte(reg);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_set_loc(uint64_t addr) {
|
|
byte(DW_CFA_set_loc);
|
|
qword(addr);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_def_cfa(uint8_t reg, uint8_t offset) {
|
|
byte(DW_CFA_def_cfa);
|
|
byte(reg);
|
|
byte(offset);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_offset(uint8_t reg, uint8_t offset) {
|
|
byte(DW_CFA_offset | reg);
|
|
byte(offset);
|
|
}
|
|
|
|
void DwarfBuf::dwarf_cfa_offset_extended_sf(uint8_t reg, int8_t offset) {
|
|
byte(DW_CFA_offset_extended_sf);
|
|
byte(reg);
|
|
byte(offset & 0x7f);
|
|
}
|
|
|
|
const char *DwarfInfo::lookupFile(const Unit *unit) {
|
|
const char *file = nullptr;
|
|
if (unit && unit->filepath()) {
|
|
file = unit->filepath()->data();
|
|
}
|
|
if (file == nullptr || strlen(file) == 0) {
|
|
return "anonFile";
|
|
}
|
|
return file;
|
|
}
|
|
|
|
void DwarfInfo::addLineEntries(TCRange range,
|
|
const Unit *unit,
|
|
const Opcode *instr,
|
|
FunctionInfo* f) {
|
|
if (unit == nullptr || instr == nullptr) {
|
|
// For stubs, just add line 0
|
|
f->m_lineTable.push_back(LineEntry(range, 0));
|
|
return;
|
|
}
|
|
Offset offset = unit->offsetOf(instr);
|
|
|
|
int lineNum = unit->getLineNumber(offset);
|
|
if (lineNum >= 0) {
|
|
f->m_lineTable.push_back(LineEntry(range, lineNum));
|
|
}
|
|
}
|
|
|
|
void DwarfInfo::transferFuncs(DwarfChunk* from, DwarfChunk* to) {
|
|
unsigned int size = from->m_functions.size();
|
|
for (unsigned int i = 0; i < size; i++) {
|
|
FunctionInfo* f = from->m_functions[i];
|
|
f->m_chunk = to;
|
|
to->m_functions.push_back(f);
|
|
}
|
|
}
|
|
|
|
void DwarfInfo::compactChunks() {
|
|
unsigned int i, j;
|
|
for (i = 1; i < m_dwarfChunks.size(); i++) {
|
|
if (m_dwarfChunks[i] == nullptr) {
|
|
break;
|
|
}
|
|
}
|
|
if (i >= m_dwarfChunks.size()) {
|
|
m_dwarfChunks.push_back(nullptr);
|
|
}
|
|
DwarfChunk* chunk = new DwarfChunk();
|
|
for (j = 0; j < i; j++) {
|
|
transferFuncs(m_dwarfChunks[j], chunk);
|
|
// unregister chunk from gdb and free chunk
|
|
unregister_gdb_chunk(m_dwarfChunks[j]);
|
|
delete(m_dwarfChunks[j]);
|
|
m_dwarfChunks[j] = nullptr;
|
|
}
|
|
m_dwarfChunks[i] = chunk;
|
|
// register compacted chunk with gdb
|
|
ElfWriter e = ElfWriter(chunk);
|
|
}
|
|
|
|
static Mutex s_lock(RankLeaf);
|
|
|
|
DwarfChunk* DwarfInfo::addTracelet(TCRange range, const char* name,
|
|
const Func *func, const Opcode *instr, bool exit, bool inPrologue) {
|
|
DwarfChunk* chunk = nullptr;
|
|
FunctionInfo* f = new FunctionInfo(range, exit);
|
|
const Unit* unit = func ? func->unit(): nullptr;
|
|
if (name) {
|
|
f->name = std::string(name);
|
|
} else {
|
|
assert(func != nullptr);
|
|
f->name = lookupFunction(func, exit, inPrologue, true);
|
|
const StringData* const *names = func->localNames();
|
|
for (int i = 0; i < func->numNamedLocals(); i++) {
|
|
f->m_namedLocals.push_back(names[i]->toCPPString());
|
|
}
|
|
}
|
|
f->file = lookupFile(unit);
|
|
|
|
TCA start = range.begin();
|
|
const TCA end = range.end();
|
|
|
|
Lock lock(s_lock);
|
|
FuncDB::iterator it = m_functions.lower_bound(range.begin());
|
|
FunctionInfo* fi = it->second;
|
|
if (it != m_functions.end() && fi->name == f->name &&
|
|
fi->file == f->file &&
|
|
start > fi->range.begin() &&
|
|
end > fi->range.end()) {
|
|
// XXX: verify that overlapping address come from jmp fixups
|
|
start = fi->range.end();
|
|
fi->range.extend(end);
|
|
m_functions[end] = fi;
|
|
m_functions.erase(it);
|
|
delete(f);
|
|
f = m_functions[end];
|
|
assert(f->m_chunk != nullptr);
|
|
f->m_chunk->clearSynced();
|
|
f->clearPerfSynced();
|
|
} else {
|
|
m_functions[end] = f;
|
|
}
|
|
|
|
addLineEntries(TCRange(start, end, range.isAstubs()), unit, instr, f);
|
|
|
|
if (f->m_chunk == nullptr) {
|
|
if (m_dwarfChunks.size() == 0 || m_dwarfChunks[0] == nullptr) {
|
|
// new chunk of base size
|
|
chunk = new DwarfChunk();
|
|
m_dwarfChunks.push_back(chunk);
|
|
} else if (m_dwarfChunks[0]->m_functions.size()
|
|
< RuntimeOption::EvalGdbSyncChunks) {
|
|
// reuse first chunk
|
|
chunk = m_dwarfChunks[0];
|
|
chunk->clearSynced();
|
|
} else {
|
|
// compact chunks
|
|
compactChunks();
|
|
m_dwarfChunks[0] = chunk = new DwarfChunk();
|
|
}
|
|
chunk->m_functions.push_back(f);
|
|
f->m_chunk = chunk;
|
|
}
|
|
|
|
if (f->m_chunk->m_functions.size() >= RuntimeOption::EvalGdbSyncChunks) {
|
|
ElfWriter e = ElfWriter(f->m_chunk);
|
|
}
|
|
|
|
return f->m_chunk;
|
|
}
|
|
|
|
void DwarfInfo::syncChunks() {
|
|
unsigned int i;
|
|
Lock lock(s_lock);
|
|
for (i = 0; i < m_dwarfChunks.size(); i++) {
|
|
if (m_dwarfChunks[i] && !m_dwarfChunks[i]->isSynced()) {
|
|
unregister_gdb_chunk(m_dwarfChunks[i]);
|
|
ElfWriter e = ElfWriter(m_dwarfChunks[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|