Arquivos
hhvm/hphp/runtime/vm/debug/dwarf.cpp
T
bsimmers cf197fee81 Collapse runtime/vm/translator's contents into runtime/vm/jit
Facebook: ~bsimmers/bin/move-vm-files.sh
2013-06-03 10:54:43 -07:00

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]);
}
}
}
}
}