in tools/hbcdump/hbcdump.cpp [291:449]
static bool executeCommand(
llvh::raw_ostream &os,
ProfileAnalyzer &analyzer,
BytecodeDisassembler &disassembler,
const std::string &commandWithOptions) {
// Parse command tokens.
llvh::SmallVector<llvh::StringRef, 8> commandTokens;
llvh::StringRef(commandWithOptions).split(commandTokens, ' ');
if (commandTokens.empty()) {
// Ignore empty input.
return false;
}
const llvh::StringRef command = commandTokens[0];
if (command == "function" || command == "fun") {
if (findAndRemoveOne(commandTokens, "-used")) {
analyzer.dumpUsedFunctionIDs();
} else if (commandTokens.size() == 1) {
analyzer.dumpFunctionStats();
} else if (commandTokens.size() == 2) {
uint32_t funcId;
if (commandTokens[1].getAsInteger(0, funcId)) {
os << "Error: cannot parse func_id as integer.\n";
return false;
}
analyzer.dumpFunctionBasicBlockStat(funcId);
} else {
printHelp(command);
return false;
}
} else if (command == "instruction" || command == "inst") {
if (commandTokens.size() == 1) {
analyzer.dumpInstructionStats();
} else {
printHelp(command);
return false;
}
} else if (command == "disassemble" || command == "dis") {
auto localOptions = findAndRemoveOne(commandTokens, "-offsets")
? DisassemblyOptions::IncludeVirtualOffsets
: DisassemblyOptions::None;
DisassemblerOptionsHolder optionsHolder(
disassembler, disassembler.getOptions() | localOptions);
if (commandTokens.size() == 1) {
disassembler.disassemble(os);
} else if (commandTokens.size() == 2) {
uint32_t funcId;
if (commandTokens[1].getAsInteger(0, funcId)) {
os << "Error: cannot parse func_id as integer.\n";
return false;
}
if (funcId >= disassembler.getFunctionCount()) {
os << "Error: no function with id: " << funcId << " exists.\n";
return false;
}
disassembler.disassembleFunction(funcId, os);
} else {
printHelp(command);
return false;
}
} else if (command == "string" || command == "str") {
if (commandTokens.size() != 2) {
printHelp(command);
return false;
}
uint32_t stringId;
if (commandTokens[1].getAsInteger(0, stringId)) {
os << "Error: cannot parse string_id as integer.\n";
return false;
}
analyzer.dumpString(stringId);
} else if (command == "filename") {
if (commandTokens.size() != 2) {
printHelp(command);
return false;
}
uint32_t filenameId;
if (commandTokens[1].getAsInteger(0, filenameId)) {
os << "Error: cannot parse filename_id as integer.\n";
return false;
}
analyzer.dumpFileName(filenameId);
} else if (command == "function-info") {
JSONEmitter json(os, /* pretty */ true);
if (commandTokens.size() == 1) {
analyzer.dumpAllFunctionInfo(json);
} else if (commandTokens.size() == 2) {
uint32_t funcId;
if (commandTokens[1].getAsInteger(0, funcId)) {
os << "Error: cannot parse func_id as integer.\n";
return false;
}
analyzer.dumpFunctionInfo(funcId, json);
} else {
printHelp(command);
return false;
}
} else if (command == "io") {
analyzer.dumpIO();
} else if (command == "summary" || command == "sum") {
analyzer.dumpSummary();
} else if (command == "block") {
analyzer.dumpBasicBlockStats();
} else if (command == "at_virtual" || command == "at-virtual") {
JSONEmitter json(os, /* pretty */ true);
if (commandTokens.size() == 2) {
uint32_t virtualOffset;
if (commandTokens[1].getAsInteger(0, virtualOffset)) {
os << "Error: cannot parse virtualOffset as integer.\n";
return false;
}
auto funcId = analyzer.getFunctionFromVirtualOffset(virtualOffset);
if (funcId.hasValue()) {
analyzer.dumpFunctionInfo(*funcId, json);
} else {
os << "Virtual offset " << virtualOffset << " is invalid.\n";
}
} else {
printHelp(command);
return false;
}
} else if (command == "at_offset" || command == "at-offset") {
JSONEmitter json(os, /* pretty */ true);
if (commandTokens.size() == 2) {
uint32_t offset;
if (commandTokens[1].getAsInteger(0, offset)) {
os << "Error: cannot parse offset as integer.\n";
return false;
}
auto funcId = analyzer.getFunctionFromOffset(offset);
if (funcId.hasValue()) {
analyzer.dumpFunctionInfo(*funcId, json);
} else {
os << "Offset " << offset << " is invalid.\n";
}
} else {
printHelp(command);
return false;
}
} else if (command == "epilogue" || command == "epi") {
analyzer.dumpEpilogue();
} else if (command == "help" || command == "h") {
// Interactive help command.
if (commandTokens.size() == 2) {
printHelp(commandTokens[1]);
} else {
printHelp();
}
return false;
} else if (command == "quit") {
// Quit command loop.
return true;
} else {
printHelp(command);
return false;
}
os << "\n";
return false;
}