本文整理汇总了C++中rose::binaryanalysis::partitioner2::Engine::partition方法的典型用法代码示例。如果您正苦于以下问题:C++ Engine::partition方法的具体用法?C++ Engine::partition怎么用?C++ Engine::partition使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类rose::binaryanalysis::partitioner2::Engine
的用法示例。
在下文中一共展示了Engine::partition方法的4个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: parseCommandLine
int
main(int argc, char *argv[]) {
ROSE_INITIALIZE;
Diagnostics::initAndRegister(&::mlog, "tool");
Settings settings;
P2::Engine engine;
engine.doingPostAnalysis(false); // not needed by this tool
std::vector<std::string> specimens = parseCommandLine(argc, argv, engine, settings);
P2::Partitioner partitioner = engine.partition(specimens);
if (settings.traceInsns || settings.traceSemantics)
::mlog[TRACE].enable();
// Find the string decoder.
if (!partitioner.functionExists(settings.decoderVa)) {
::mlog[FATAL] <<"cannot find decoder function at " <<StringUtility::addrToString(settings.decoderVa) <<"\n";
exit(1);
}
if (settings.synthesized) {
processSynthesizedCalls(partitioner, settings);
} else {
processExistingCalls(partitioner, settings);
}
}
示例2: parseCommandLine
int
main(int argc, char *argv[]) {
// Parse the command-line switches
P2::Engine engine;
Settings settings;
std::vector<std::string> args = parseCommandLine(argc, argv, engine, settings);
if (args.empty()) {
mlog[FATAL] <<"no binary specimen specified; see --help\n";
exit(1);
}
// Parse the binary specimen. We're not actually adding it to the AST.
P2::Partitioner binary = engine.partition(args);
// Process the binary to add its instructions to the source template
BinaryToSource(settings.generator).generateSource(binary, std::cout);
}
示例3: specimen
int
main(int argc, char *argv[]) {
// This paragraph initializes the ROSE library, generates the man page for this tool, does command-line parsing for quite a
// few switches including "--help", loads various specimen resources (ELF/PE, running process, raw memory dumps, etc),
// disassembles, and partitions. We could have called Engine::frontend() and done it all in one function call, but then we
// wouldn't have a Partitioner2::Partitioner object that we need below.
std::string purpose = "demonstrate inter-function disassembly";
std::string description =
"Disassembles and partitions the specimen(s), then tries to disassemble things between the functions.";
P2::Engine engine;
std::vector<std::string> specimens = engine.parseCommandLine(argc, argv, purpose, description).unreachedArgs();
P2::Partitioner partitioner = engine.partition(specimens);
// The partitioner's address usage map (AUM) describes what part of memory has been disassembled as instructions or
// data. We're interested in the unused parts between the lowest and highest disassembled addresses, so we loop over those
// parts. The hull() is the entire used interval -- lowest to highest addresses used regardless of the unused areas in the
// middle. An AddressInterval evaluated in boolean context returns false if it's empty.
rose_addr_t va = partitioner.aum().hull().least();
while (AddressInterval unused = partitioner.aum().nextUnused(va)) {
// Is the unused area beyond the last thing compiled? We're only interested in the stuff between functions. This
// check also means that unused.greatest()+1 will not overflow, which simplifies later code. Overflows are easy to
// trigger when the specimen's word size is the same as ROSE's word size.
if (unused.least() > partitioner.aum().hull().greatest())
break;
// The unused address might be in the middle of some very large unmapped area of memory, or perhaps in an area that
// doesn't have execute permission (the partitioner will only disassemble at addresses that we've marked as
// executable). A naive implementation would just increment to the next address and try again, but that could take a
// very long time. This "if" statement will give us the next executable address that falls within the unused interval
// if possible. The address is assigned to "va" if possible.
if (!engine.memoryMap().within(unused).require(MemoryMap::EXECUTABLE).next().assignTo(va)) {
va = unused.greatest() + 1; // won't overflow because of check above
continue;
}
// "va" now points to an executable address that the partitioner doesn't know about yet.
ASSERT_require(engine.memoryMap().at(va).require(MemoryMap::EXECUTABLE).exists());
ASSERT_forbid(partitioner.aum().instructionExists(va));
std::cout <<"unused address " <<StringUtility::addrToString(va) <<"\n";
// Cause the partitioner to discover (disassemble) one basic block. This doesn't add the basic block to the
// partitioner or change the partitioner in any way. If the BB isn't something we want to keep then just forget about
// it and garbage collection will reclaim the memory.
P2::BasicBlock::Ptr bb = partitioner.discoverBasicBlock(va);
if (!isGoodBasicBlock(bb)) {
++va;
continue;
}
std::cout <<" disassembled " <<bb->printableName() <<"\n";
// Inform the partitioner that we wish to keep this BB.
partitioner.attachBasicBlock(bb);
// This BB was not reachable by any previous CFG edge, therefore it doesn't belong to any function. In order for it to
// show up in the eventual AST we need to add it to some function (the ROSE AST has a requirement that every basic
// block belongs to a function, although the partitioner can easily cope with the other case). The easiest way in this
// situation is to just create a new function whose entry block is this BB. Creating a function doesn't modify the
// partitioner in any way, so we need to also attach the function to the partitioner.
P2::Function::Ptr function = P2::Function::instance(va, SgAsmFunction::FUNC_USERDEF);
function->insertBasicBlock(va); // allowed only before attaching function to partitioner
partitioner.attachOrMergeFunction(function);
// This basic block might be the first block of a whole bunch that are connected by as yet undiscovered CFG edges. We
// can recursively discover and attach all those blocks with one Engine method. There are also Partitioner methods to
// do similar things, but they're lower level.
engine.runPartitionerRecursive(partitioner);
}
// We've probably added a bunch more functions and basic blocks to the partitioner, but we haven't yet assigned the basic
// blocks discovered by Engine::runPartitionerRecursive to any functions. We might also need to assign function labels
// from ELF/PE information, re-run some analysis, etc., so do that now.
engine.runPartitionerFinal(partitioner);
// Most ROSE analysis is performed on an abstract syntax tree, so generate one. If the specime is an ELF or PE container
// then the returned global block will also be attached somewhere below a SgProject node, otherwise the returned global
// block is the root of the AST and there is no project (e.g., like when the specimen is a raw memory dump).
SgAsmBlock *gblock = P2::Modules::buildAst(partitioner, engine.interpretation());
// Generate an assembly listing. These unparser properties are all optional, but they result in more informative assembly
// listings.
AsmUnparser unparser;
unparser.set_registers(partitioner.instructionProvider().registerDictionary());
unparser.add_control_flow_graph(ControlFlow().build_block_cfg_from_ast<ControlFlow::BlockGraph>(gblock));
unparser.staticDataDisassembler.init(engine.disassembler());
unparser.unparse(std::cout, gblock);
}
示例4: debugger
int
main(int argc, char *argv[]) {
ROSE_INITIALIZE;
Diagnostics::initAndRegister(&mlog, "tool");
// Parse the command-line to configure the partitioner engine, obtain the executable and its arguments, and generate a man
// page, adjust global settings, etc. This demo tool has no switches of its own, which makes this even easier. For a
// production tool, it's probably better to obtain the parser and register only those switches we need (e.g., no need for
// AST generation switches since we skip that step), to set it up to use our own diagnostic stream instead of exceptions,
// and to adjust this tool's synopsis in the documentation. Examples of all of these can be found in other demos.
P2::Engine engine;
engine.doingPostAnalysis(false); // no need for any post-analysis phases (user can override on cmdline)
std::vector<std::string> command;
try {
command = engine.parseCommandLine(argc, argv, purpose, description).unreachedArgs();
} catch (const std::runtime_error &e) {
mlog[FATAL] <<"invalid command-line: " <<e.what() <<"\n";
exit(1);
}
if (command.empty()) {
mlog[FATAL] <<"no executable specified\n";
exit(1);
}
// Since we'll be tracing this program's execution, we might as well disassemble the process's memory directly. That way we
// don't have to worry about ROSE mapping the specimen to the same virtual address as the kernel (which might be using
// address randomization). We can stop short of generating the AST because we won't need it.
BinaryAnalysis::BinaryDebugger debugger(command);
std::string specimenResourceName = "proc:noattach:" + StringUtility::numberToString(debugger.isAttached());
P2::Partitioner partitioner = engine.partition(specimenResourceName);
partitioner.memoryMap()->dump(std::cerr); // show the memory map as a debugging aid
// Create a global control flow graph whose vertices are instructions from a global CFG whose verts are mostly basic
// blocks.
InsnCfg insnCfg;
const P2::ControlFlowGraph &bbCfg = partitioner.cfg();
BOOST_FOREACH (const P2::ControlFlowGraph::Vertex &bbVert, bbCfg.vertices()) {
if (P2::BasicBlock::Ptr bb = isBasicBlock(bbVert)) {
const std::vector<SgAsmInstruction*> &insns = bb->instructions();
// Each basic block has one or more instructions that need to be inserted into our instruction control flow graph
// with edges from each instruction to the next. The insertEdgeWithVertices automatically inserts missing
// vertices, and doesn't insert vertices that already exist, making it convenient for this type of construction.
for (size_t i=1; i<insns.size(); ++i)
insnCfg.insertEdgeWithVertices(insns[i-1], insns[i]);
// The final instruction of this block needs to flow into each of the initial instructions of the successor basic
// blocks. Be careful that the successors are actually existing basic blocks. Note that in ROSE's global CFG, a
// function call has at least two successors: the function being called (normal edges), and the address to which
// the function returns ("callret" edges). There are other types of edges too, but we want only the normal edges.
BOOST_FOREACH (const P2::ControlFlowGraph::Edge &bbEdge, bbVert.outEdges()) {
if (bbEdge.value().type() == P2::E_NORMAL) {
if (P2::BasicBlock::Ptr target = isBasicBlock(*bbEdge.target()))
insnCfg.insertEdgeWithVertices(insns.back(), target->instructions()[0]);
}
}
}
}
mlog[INFO] <<"block CFG: "
<<StringUtility::plural(bbCfg.nVertices(), "vertices", "vertex") <<", "
<<StringUtility::plural(bbCfg.nEdges(), "edges") <<"\n";
mlog[INFO] <<"insn CFG: "
<<StringUtility::plural(insnCfg.nVertices(), "vertices", "vertex") <<", "
<<StringUtility::plural(insnCfg.nEdges(), "edges") <<"\n";
// Run the executable to obtain a trace. We use the instruction pointer to look up a SgAsmInstruction in the insnCfg and
// thus map the trace onto the instruction CFG.
mlog[INFO] <<"running subordinate to obtain trace: " <<boost::join(command, " ") <<"\n";
std::set<rose_addr_t> missingAddresses;
Trace trace;
while (!debugger.isTerminated()) {
// Find the instruction CFG vertex corresponding to the current execution address. It could be that the execution
// address doesn't exist in the CFG, and this can be caused by a number of things including failure of ROSE to
// statically find the address, dynamic libraries that weren't loaded statically, etc.
rose_addr_t va = debugger.executionAddress();
InsnCfg::ConstVertexIterator vertex = insnCfg.findVertexKey(va);
if (!insnCfg.isValidVertex(vertex)) {
missingAddresses.insert(va);
} else {
trace.append(vertex->id());
}
debugger.singleStep();
}
mlog[INFO] <<"subordinate " <<debugger.howTerminated() <<"\n";
mlog[INFO] <<"trace length: " <<StringUtility::plural(trace.size(), "instructions") <<"\n";
Diagnostics::mfprintf(mlog[INFO])("overall burstiness: %6.2f%%\n", 100.0 * trace.burstiness());
mlog[INFO] <<"distinct executed addresses missing from CFG: " <<missingAddresses.size() <<"\n";
// Print a list of CFG vertices that were never reached. We use std::cout rather than diagnostics because this is one of
// the main outputs of this demo. The "if" condition is constant time.
BOOST_FOREACH (const InsnCfg::Vertex &vertex, insnCfg.vertices()) {
if (!trace.exists(vertex.id()))
std::cout <<"not executed: " <<unparseInstructionWithAddress(vertex.value()) <<"\n";
}
// Print list of addresses that were executed but did not appear in the CFG
BOOST_FOREACH (rose_addr_t va, missingAddresses)
std::cout <<"missing address: " <<StringUtility::addrToString(va) <<"\n";
// Print those branch instructions that were executed by the trace but always took the same branch. Just to mix things up,
//.........这里部分代码省略.........