Arquivos
hhvm/hphp/runtime/eval/debugger/cmd/cmd_instrument.cpp
T
Edwin Smith 12c676bc8b Litstr must die, episode V.
Removed the litstr overloads of Array::rvalAt, rvalAtRef, lval,
lvalPtr, lvalAt, and set.  The main one left to do is operator[].

Fixed a bug in f_get_html_translation_table() where we were copying
the null terminator of what should be a one-character string, thus
creating a two-character string with s[1] == 0.  (cc @jdelong)

In class Extension, store a String for the name instead of
const char*.  cc @sgolemon
2013-04-30 09:27:06 -07:00

278 linhas
9.4 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 <runtime/eval/debugger/cmd/cmd_instrument.h>
#include <runtime/vm/instrumentation.h>
#include <runtime/ext/ext_file.h>
namespace HPHP { namespace Eval {
///////////////////////////////////////////////////////////////////////////////
void CmdInstrument::sendImpl(DebuggerThriftBuffer &thrift) {
DebuggerCommand::sendImpl(thrift);
thrift.write(m_type);
thrift.write(m_enabled);
assert(m_instPoints);
InstPointInfo::SendImpl(*m_instPoints, thrift);
}
void CmdInstrument::recvImpl(DebuggerThriftBuffer &thrift) {
DebuggerCommand::recvImpl(thrift);
thrift.read(m_type);
thrift.read(m_enabled);
InstPointInfo::RecvImpl(m_ips, thrift);
}
bool CmdInstrument::help(DebuggerClient *client) {
client->helpTitle("Instrument Command");
// TODO: more functionalities
client->helpCmds("inst here <file> [desc]",
"inject <file> to here",
"inst <func>() <file> [desc]",
"inject <file> to the entry point of <func>",
"inst [l]ist",
"list injections",
"inst [c]lear",
"clear all injections",
nullptr);
client->helpBody(
"Use this command to instrument the program"
);
return true;
}
bool CmdInstrument::onClient(DebuggerClient *client) {
if (DebuggerCommand::onClient(client)) return true;
if (client->argCount() == 1) {
if (client->argValue(1) == "list" || client->argValue(1) == "l") {
listInst(client);
return true;
}
if (client->argValue(1) == "clear" || client->argValue(1) == "c") {
clearInst(client);
return true;
}
}
if (client->argCount() < 2 || client->argValue(1) == "help") {
return help(client);
}
std::string loc = client->argValue(1);
std::string file = client->argValue(2);
std::string desc;
if (client->argCount() >= 3) {
desc = client->argValue(3);
}
Variant code = f_file_get_contents(file.c_str());
if (code.isNull()) {
client->error("Unable to read from file %s", file.c_str());
return false;
}
m_instPoints = client->getInstPoints();
if (loc == "here") {
InstPointInfoPtr ipi(new InstPointInfo());
ipi->setLocHere();
ipi->m_code = (std::string) code.toString();
ipi->m_desc = desc;
m_instPoints->push_back(ipi);
} else if (loc.rfind("()") == loc.size() - 2){
InstPointInfoPtr ipi(new InstPointInfo());
ipi->setLocFuncEntry(loc.substr(0, loc.size() - 2));
ipi->m_code = (std::string) code.toString();
ipi->m_desc = desc;
m_instPoints->push_back(ipi);
} else {
client->error("Not implemented\n");
return true;
}
m_type = ActionWrite;
CmdInstrumentPtr instCmdPtr = client->xend<CmdInstrument>(this);
if (!instCmdPtr->m_enabled) {
client->error("Instrumentation is not enabled on the server");
}
client->setInstPoints(instCmdPtr->m_ips);
CmdInstrument::PrintInstPoints(client);
return true;
}
static const StaticString s_valid("valid");
static const StaticString s_desc("desc");
static const StaticString s_type("type");
static const StaticString s_file_line("file_line");
static const StaticString s_file("file");
static const StaticString s_line("line");
static const StaticString s_func_entry("func_entry");
static const StaticString s_func("func");
void CmdInstrument::setClientOutput(DebuggerClient *client) {
// Output all instrumentation point info
client->setOutputType(DebuggerClient::OTValues);
Array values;
InstPointInfoPtrVec* ips = client->getInstPoints();
for (unsigned int i = 0; i < ips->size(); i++) {
InstPointInfoPtr ipi = (*ips)[i];
Array instpoint;
instpoint.set(s_valid, ipi->m_valid);
instpoint.set(s_desc, ipi->m_desc);
if (ipi->m_locType == InstPointInfo::LocFileLine) {
instpoint.set(s_type, s_file_line);
instpoint.set(s_file, ipi->m_file);
instpoint.set(s_line, ipi->m_line);
} else if (ipi->m_locType == InstPointInfo::LocFuncEntry) {
instpoint.set(s_type, s_func_entry);
instpoint.set(s_func, ipi->m_func);
}
values.append(instpoint);
}
client->setOTValues(values);
}
bool CmdInstrument::onServer(DebuggerProxy *proxy) {
m_instPoints = &m_ips;
m_enabled = true;
if (m_type == ActionRead) {
readFromTable(proxy);
} else if (m_type == ActionWrite) {
validateAndWriteToTable(proxy);
}
return proxy->sendToClient(this);
}
void CmdInstrument::readFromTable(DebuggerProxy *proxy) {
proxy->readInjTablesFromThread();
m_ips.clear();
if (!proxy->getInjTables()) {
// nothing there
return;
}
// Bytecode address
VM::InjectionTableInt64* tablePC =
proxy->getInjTables()->getInt64Table(VM::InstHookTypeBCPC);
if (tablePC) {
for (VM::InjectionTableInt64::const_iterator it = tablePC->begin();
it != tablePC->end(); ++it) {
const VM::Injection* inj = it->second;
InstPointInfoPtr ipi(new InstPointInfo());
ipi->m_valid = true;
if (inj->m_desc) {
ipi->m_desc = inj->m_desc->data();
}
ipi->m_locType = InstPointInfo::LocFileLine;
// TODO use pc to figure out m_file and m_line
// uchar* pc = (uchar*)it->first;
m_ips.push_back(ipi);
}
}
VM::InjectionTableSD* tableFEntry =
proxy->getInjTables()->getSDTable(VM::InstHookTypeFuncEntry);
if (tableFEntry) {
for (VM::InjectionTableSD::const_iterator it = tableFEntry->begin();
it != tableFEntry->end(); ++it) {
const VM::Injection* inj = it->second;
InstPointInfoPtr ipi(new InstPointInfo());
ipi->m_valid = true;
if (inj->m_desc) {
ipi->m_desc = inj->m_desc->data();
}
ipi->m_func = it->first->data();
ipi->m_locType = InstPointInfo::LocFuncEntry;
m_ips.push_back(ipi);
}
}
}
void CmdInstrument::validateAndWriteToTable(DebuggerProxy *proxy) {
if (!proxy->getInjTables()) {
proxy->setInjTables(new VM::InjectionTables());
}
VM::InjectionTableInt64* tablePC = nullptr;
VM::InjectionTableSD* tableFEntry = nullptr;
for (int i = 0; i < (int)m_ips.size(); i++) {
InstPointInfoPtr ipi = m_ips[i];
const VM::Injection* inj =
VM::InjectionCache::GetInjection(ipi->m_code, ipi->m_desc);
if (!inj) { // error in the code
continue;
}
if (ipi->m_locType == InstPointInfo::LocHere ||
ipi->m_locType == InstPointInfo::LocFileLine) {
// bytecode address
const uchar *pc = ipi->lookupPC();
if (pc == nullptr) {
continue;
}
if (tablePC == nullptr) {
tablePC = new VM::InjectionTableInt64();
}
ipi->m_valid = true;
(*tablePC)[(int64_t)pc] = inj;
}
if (ipi->m_locType == InstPointInfo::LocFuncEntry) {
StackStringData sd(ipi->m_func.c_str(), ipi->m_func.size(), CopyString);
const StringData* sdCache = VM::InjectionCache::GetStringData(&sd);
if (tableFEntry == nullptr) {
tableFEntry = new VM::InjectionTableSD();
}
ipi->m_valid = true;
(*tableFEntry)[sdCache] = inj;
}
}
proxy->getInjTables()->setInt64Table(VM::InstHookTypeBCPC, tablePC);
proxy->getInjTables()->setSDTable(VM::InstHookTypeFuncEntry, tableFEntry);
proxy->writeInjTablesToThread();
}
void CmdInstrument::listInst(DebuggerClient *client) {
m_type = ActionRead;
m_instPoints = client->getInstPoints();
CmdInstrumentPtr instCmdPtr = client->xend<CmdInstrument>(this);
client->setInstPoints(instCmdPtr->m_ips);
PrintInstPoints(client);
}
void CmdInstrument::clearInst(DebuggerClient *client) {
m_type = ActionWrite;
m_instPoints = client->getInstPoints();
m_instPoints->clear();
CmdInstrumentPtr instCmdPtr = client->xend<CmdInstrument>(this);
client->setInstPoints(instCmdPtr->m_ips);
PrintInstPoints(client);
}
void CmdInstrument::PrintInstPoints(DebuggerClient *client) {
InstPointInfoPtrVec* ips = client->getInstPoints();
int size = ips->size();
client->print("%d instrumentation points", size);
for (int i = 0; i < size; i++) {
InstPointInfoPtr ipi = (*ips)[i];
if (ipi->m_locType == InstPointInfo::LocFileLine) {
client->print(" %d\t%s\t%s\tfile:\t%s:%d", i,
ipi->m_valid ? "valid" : "invalid",
ipi->m_desc.c_str(), ipi->m_file.c_str(), ipi->m_line);
} else if (ipi->m_locType == InstPointInfo::LocFuncEntry) {
client->print(" %d\t%s\t%s\tfunc entry:\t%s", i,
ipi->m_valid ? "valid" : "invalid",
ipi->m_desc.c_str(), ipi->m_func.c_str());
}
}
}
///////////////////////////////////////////////////////////////////////////////
}}