SgAsmInterpretation* RSIM_ColdFire::parseMainExecutable(RSIM_Process *process) { namespace P2 = rose::BinaryAnalysis::Partitioner2; using namespace Sawyer::CommandLine; // This is raw hardware, so assume that all the arguments are for loading the specimen. P2::Engine engine; Parser parser; parser .purpose("initializes ColdFire memory") .version(std::string(ROSE_SCM_VERSION_ID).substr(0, 8), ROSE_CONFIGURE_DATE) .chapter(1, "ROSE Command-line Tools") .doc("Synopsis", "@prop{programName} ... -- [@v{loader_switches}] @v{resources}") .doc("Description", "This part of the simulator command-line is responsible for configuring how @v{resources} are loaded into " "simulated FreeScale ColdFire system memory. If switches are provided here they must be separated from " "simulator switches with a \"--\" to prevent the simulator itself from interpreting them.\n\n" + engine.specimenNameDocumentation()) .with(Switch("help", 'h') .hidden(true) .action(showHelpAndExit(0))) .with(engine.loaderSwitches()); std::vector<std::string> resources = parser.parse(exeArgs()).apply().unreachedArgs(); engine.isaName("coldfire"); MemoryMap::Ptr map = engine.loadSpecimens(resources); process->mem_transaction_start("specimen main memory"); *process->get_memory() = *map; // shallow copy, new segments point to same old data // The initial program counter is stored at address 4, the second entry in the interrupt vector. uint32_t initialIpBe = 0; if (!map->at(4).limit(sizeof initialIpBe).read((uint8_t*)&initialIpBe)) { mlog[FATAL] <<"failed to read initial program counter from address zero\n"; exit(1); } uint32_t initialIp = ByteOrder::be_to_host(initialIpBe); process->entryPointOriginalVa(initialIp); process->entryPointStartVa(initialIp); process->disassembler(engine.obtainDisassembler()); return engine.interpretation(); // probably null since args not likely to be ELF or PE }
// Describe and parse the command-line static std::vector<std::string> parseCommandLine(int argc, char *argv[], P2::Engine &engine, Settings &settings) { using namespace Sawyer::CommandLine; std::string purpose = "compares actual execution with known instructions"; std::string description = "Reads instruction addresses from a file, the so-called \"expected\" addresses and and then executes the specimen " "and compares actual executed addresses with the expected addresses. An actual executed address falls into one of " "three categories: (1) the address is an expected address, or else (2) the address is not mapped, or else (3) the " "address not expected.\n\n" "One method of obtaining a list of expected addresses is to use the @man{recursiveDisassemble}{--help} tool's " "@s{list-instruction-addressses}{noerror} switch. Although this produces output that contains instruction sizes " "as well as addresses, @prop{programName} ignores the sizes. This can be used to test whether a process executes any " "instructions that were not also disassembled, thereby testing some aspect of the disassembly quality."; // The parser is the same as that created by Engine::commandLineParser except we don't need any disassemler or partitioning // switches since this tool doesn't disassemble or partition. Parser parser; parser .purpose(purpose) .version(std::string(ROSE_SCM_VERSION_ID).substr(0, 8), ROSE_CONFIGURE_DATE) .chapter(1, "ROSE Command-line Tools") .doc("Synopsis", "@prop{programName} [@v{switches}] @v{address_file} @v{specimen_name} @v{specimen_arguments}...") .doc("Description", description) .doc("Specimens", engine.specimenNameDocumentation()) .with(engine.engineSwitches()) .with(engine.loaderSwitches()); SwitchGroup tool("Tool specific switches"); tool.name("tool"); tool.insert(Switch("map") .argument("how", enumParser(settings.mapSource) ->with("native", MAP_NATIVE) ->with("rose", MAP_ROSE)) .doc("Specifies how the memory map should be obtained, where @v{how} is either \"native\" to obtain the map " "from a running process, or \"rose\" to obtain the map by parsing the specimen container with ROSE. When " "obtained natively the map may contain addresses that were not visible to the original disassembler. When " "obtained from ROSE the map might not be identical to map actually used by the process. The default is \"" + std::string(MAP_ROSE==settings.mapSource?"rose":"native") + "\".")); tool.insert(Switch("trace") .intrinsicValue(true, settings.trace) .doc("When @s{trace} is specified each execution address is printed to a file named \"@v{pid}.trace\" where " "@v{pid} is the process ID of the specimen. Each line of the file will contain the following " "space-separated fields:" "@bullet{The hexadecimal address of the instruction that was executed.}" "@bullet{The number of times this address has been executed so far.}" "@bullet{The letter '1' or '0' to indicate whether the address known (from the @v{address_file}) or not.}" "The @s{no-trace} switch disables tracing. The default is to " + std::string(settings.trace?"":"not ") + "produce a trace.")); tool.insert(Switch("no-trace") .key("trace") .intrinsicValue(false, settings.trace) .hidden(true)); tool.insert(Switch("show-expected") .intrinsicValue(true, settings.showExpected) .doc("List addresses that were expected and show how many times each was executed. The output will be one line " "per address, containing a hexadecimal address and a decimal count separated by white space. The " "@s{no-show-expected} switch turns this listing off. The default is to " + std::string(settings.showExpected?"":"not ") + "show this information.")); tool.insert(Switch("no-show-expected") .key("show-expected") .intrinsicValue(false, settings.showExpected) .hidden(true)); tool.insert(Switch("show-unexpected") .intrinsicValue(true, settings.showUnexpected) .doc("List the addresses that were executed where no instruction was expected. The output will be one line per " "address, containing a hexadecimal address and the number of times the address was executed separated by " "white space. The @s{no-show-unexpected} switch turns this listing off. The default is to " + std::string(settings.showUnexpected?"":"not ") + "show this information.")); tool.insert(Switch("no-show-unexpected") .key("show-unexpected") .intrinsicValue(false, settings.showUnexpected) .hidden(true)); tool.insert(Switch("show-unmapped") .intrinsicValue(true, settings.showUnmapped) .doc("List addresses that were executed but are not present in the memory map. These are probably instructions " "that belong to the dynamic linker, dynamically-linked libraries, or virtual dynamic shared objects. The " "@s{no-show-unmapped} switch turns this listing off. The default is to " + std::string(settings.showUnmapped?"":"not ") + "show this information.")); tool.insert(Switch("no-show-unmapped") .key("show-unmapped") .intrinsicValue(false, settings.showUnmapped) .hidden(true)); return parser.with(tool).parse(argc, argv).apply().unreachedArgs(); }