Ejemplo n.º 1
0
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();
}