int main(int argc, char *argv[]) { ROSE_INITIALIZE; Diagnostics::initAndRegister(&mlog, "tool"); // Parse command line Settings settings; std::vector<std::string> args = parseCommandLine(argc, argv, settings).unreachedArgs(); if (args.size()!=2) throw std::runtime_error("invalid usage; see --help"); // Load the CSV files FunctionByAddress code1, data1, code2, data2; readCsvFile(args[0], code1 /*out*/, data1 /*out*/); readCsvFile(args[1], code2 /*out*/, data2 /*out*/); showStats(FileSystem::Path(args[0]).filename().string(), code1, data1, FileSystem::Path(args[1]).filename().string(), code2, data2); std::cout <<"\n"; // Parse the specimen if (!settings.specimenName.empty()) { P2::Engine engine; MemoryMap::Ptr map = engine.loadSpecimens(settings.specimenName); InstructionProvider::Ptr insns = InstructionProvider::instance(engine.obtainDisassembler(), map); map->dump(std::cout); listInstructions(insns, map, code1, code2); } }
size_t SgAsmGenericFile::read_content(const MemoryMap::Ptr &map, rose_addr_t start_va, void *dst_buf, rose_addr_t size, bool strict) { ROSE_ASSERT(map!=NULL); /* Note: This is the same algorithm as used by MemoryMap::read() except we do it here so that we have an opportunity * to track the file byte references. */ size_t ncopied = 0; while (ncopied < size) { rose_addr_t va = start_va + ncopied; size_t nread = map->at(va).limit(size-ncopied).singleSegment().read((uint8_t*)dst_buf+ncopied).size(); if (0==nread) break; if (get_tracking_references()) { assert(map->at(va).exists()); const MemoryMap::Node &me = *(map->at(va).findNode()); if (me.value().buffer()->data()==&(get_data()[0])) { /* We are tracking file reads and this segment does, indeed, point into the file. */ size_t file_offset = me.value().offset() + va - me.key().least(); mark_referenced_extent(file_offset, nread); } } ncopied += nread; } if (ncopied<size) { if (strict) throw MemoryMap::NotMapped("SgAsmGenericFile::read_content() no mapping", map, start_va+ncopied); memset((char*)dst_buf+ncopied, 0, size-ncopied); /*zero pad result if necessary*/ } return ncopied; }
static void listInstructions(const InstructionProvider::Ptr &insns, const MemoryMap::Ptr &map, const FunctionByAddress &code1, FunctionByAddress &code2) { std::ostream &out = std::cout; static const size_t insnWidth = 110; rose_addr_t va1 = code1.hull().least(); rose_addr_t va2 = code2.hull().least(); rose_addr_t va = std::min(va1, va2); rose_addr_t expectedVa = va; AsmUnparser unparser; while (va<=code1.hull().greatest() || va<=code2.hull().greatest()) { // Address and contents if (va != expectedVa) out <<"\n"; // visual cue that addresses are not sequential here std::ostringstream ss; size_t size; if (!map->at(va).require(MemoryMap::EXECUTABLE).exists()) { ss <<StringUtility::addrToString(va) <<": " <<(map->at(va).exists() ? "not executable" : "not mapped"); size = 1; } else if (SgAsmInstruction *insn = (*insns)[va]) { unparser.unparse(ss, insn); size = insn->get_size(); } else { ss <<StringUtility::addrToString(va) <<": bad instruction"; size = 1; } std::vector<std::string> lines = StringUtility::split('\n', ss.str()); while (lines.size()>0 && lines[lines.size()-1]=="") lines.pop_back(); for (size_t i=0; i<lines.size(); ++i) { if (i+1 < lines.size()) { out <<lines[i] <<"\n"; } else { out <<std::setw(insnWidth) <<std::left <<lines[i]; } } // Functions owning Sawyer::Optional<rose_addr_t> f1 = code1.getOptional(va); Sawyer::Optional<rose_addr_t> f2 = code2.getOptional(va); out <<"\t" <<std::setw(10) <<std::left <<(f1 ? StringUtility::addrToString(*f1) : std::string("none")); out <<"\t" <<std::setw(10) <<std::left <<(f2 ? StringUtility::addrToString(*f2) : std::string("none")); out <<" " <<(f1.isEqual(f2) ? "" : "<---") <<"\n"; // Advance address pointer rose_addr_t next = va + size; expectedVa = next; FunctionByAddress::ConstIntervalIterator i1 = code1.upperBound(va); if (i1!=code1.nodes().end() && i1->least() < next) next = i1->least(); FunctionByAddress::ConstIntervalIterator i2 = code2.upperBound(va); if (i2!=code2.nodes().end() && i2->least() < next) next = i2->least(); if (!map->atOrAfter(next).next().assignTo(va)) break; } }
uint64_t readMemory(rose_addr_t va) const { MemoryMap::Ptr map = ConcreteSemantics::MemoryState::promote(ops_->currentState()->memoryState())->memoryMap(); uint8_t buf[16]; memset(buf, 0, sizeof buf); size_t nBytes = wordSize_ / 8; ASSERT_require(sizeof(buf) >= nBytes); map->at(va).limit(nBytes).read(buf); uint64_t retval = 0; for (size_t i=0; i<nBytes; ++i) retval |= buf[i] << (8*i); // FIXME[Robb P. Matzke 2015-05-19]: this is only little endian return retval; }
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 }
void reset(const MemoryMap::Ptr &map) { BOOST_FOREACH (MemoryMap::Segment &segment, map->segments()) segment.buffer()->copyOnWrite(true); // prevent the VM from changing the real map BaseSemantics::StatePtr state = ops_->currentState()->clone(); state->clear(); ConcreteSemantics::MemoryStatePtr memState = ConcreteSemantics::MemoryState::promote(state->memoryState()); memState->memoryMap(map); ops_->currentState(state); BaseSemantics::SValuePtr sp = ops_->number_(wordSize_, stackVa_); ops_->writeRegister(regSp_, sp); ops_->writeMemory(regSs_, sp, ops_->number_(wordSize_, returnMarker_), ops_->boolean_(true)); }
int main(int argc, char *argv[]) { ROSE_INITIALIZE; BinaryAnalysis::Partitioner2::Engine engine; Settings settings; std::vector<std::string> specimenNames = parseCommandLine(argc, argv, engine, settings /*in,out*/); BinaryAnalysis::MagicNumber analyzer; analyzer.maxBytesToCheck(settings.maxBytes); MemoryMap::Ptr map = engine.loadSpecimens(specimenNames); map->dump(mlog[INFO]); size_t step = std::max(size_t(1), settings.step); AddressInterval limits = settings.limits.isEmpty() ? map->hull() : (settings.limits & map->hull()); Sawyer::Container::IntervalSet<AddressInterval> addresses(*map); addresses.intersect(limits); size_t nPositions = addresses.size() / step; mlog[INFO] <<"approximately " <<StringUtility::plural(nPositions, "positions") <<" to check\n"; { Sawyer::ProgressBar<size_t> progress(nPositions, mlog[INFO], "positions"); for (rose_addr_t va=limits.least(); va<=limits.greatest() && map->atOrAfter(va).next().assignTo(va); va+=step, ++progress) { std::string magicString = analyzer.identify(map, va); if (magicString!="data") { // runs home to Momma when it gets confused uint8_t buf[8]; size_t nBytes = map->at(va).limit(sizeof buf).read(buf).size(); std::cout <<StringUtility::addrToString(va) <<" |" <<leadingBytes(buf, nBytes) <<" | " <<magicString <<"\n"; } if (va==limits.greatest()) break; // prevent overflow at top of address space } } }
/* Print some debugging information */ void SgAsmPEFileHeader::dump(FILE *f, const char *prefix, ssize_t idx) const { char p[4096]; if (idx>=0) { sprintf(p, "%sPEFileHeader[%zd].", prefix, idx); } else { sprintf(p, "%sPEFileHeader.", prefix); } int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p)); time_t t = p_e_time; char time_str[128]; struct tm *tm = localtime(&t); if (tm) { strftime(time_str, sizeof time_str, "%c", tm); } else { strcpy(time_str, "INVALID"); } SgAsmGenericHeader::dump(f, p, -1); fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_cpu_type", p_e_cpu_type, p_e_cpu_type); fprintf(f, "%s%-*s = %u\n", p, w, "e_nsections", p_e_nsections); fprintf(f, "%s%-*s = %u (%s)\n", p, w, "e_time", p_e_time, time_str); fprintf(f, "%s%-*s = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, w, "e_coff_symtab", p_e_coff_symtab, p_e_coff_symtab); fprintf(f, "%s%-*s = %u\n", p, w, "e_coff_nsyms", p_e_coff_nsyms); if (p_coff_symtab) { fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "coff_symtab", p_coff_symtab->get_id(), p_coff_symtab->get_name()->get_string(true).c_str()); } else { fprintf(f, "%s%-*s = none\n", p, w, "coff_symtab"); } fprintf(f, "%s%-*s = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, w, "e_nt_hdr_size", p_e_nt_hdr_size, p_e_nt_hdr_size); fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_flags", p_e_flags, p_e_flags); fprintf(f, "%s%-*s = 0x%04x %s\n", p, w, "e_opt_magic", p_e_opt_magic, 0x10b == p_e_opt_magic ? "PE32" : (0x20b == p_e_opt_magic ? "PE32+" : "other")); fprintf(f, "%s%-*s = %u.%u\n", p, w, "linker_vers", p_e_lmajor, p_e_lminor); fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_code_size", p_e_code_size, p_e_code_size); fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_data_size", p_e_data_size, p_e_data_size); fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_bss_size", p_e_bss_size, p_e_bss_size); fprintf(f, "%s%-*s = %s\n", p, w, "e_code_rva", p_e_code_rva.to_string().c_str()); fprintf(f, "%s%-*s = %s\n", p, w, "e_data_rva", p_e_data_rva.to_string().c_str()); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_section_align", p_e_section_align, p_e_section_align); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_file_align", p_e_file_align, p_e_file_align); fprintf(f, "%s%-*s = %u.%u\n", p, w, "os_vers", p_e_os_major, p_e_os_minor); fprintf(f, "%s%-*s = %u.%u\n", p, w, "user_vers", p_e_user_major, p_e_user_minor); fprintf(f, "%s%-*s = %u.%u\n", p, w, "subsys_vers", p_e_subsys_major, p_e_subsys_minor); fprintf(f, "%s%-*s = %u\n", p, w, "e_reserved9", p_e_reserved9); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_image_size", p_e_image_size, p_e_image_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_header_size", p_e_header_size, p_e_header_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_file_checksum", p_e_file_checksum, p_e_file_checksum); fprintf(f, "%s%-*s = %u\n", p, w, "e_subsystem", p_e_subsystem); fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_dll_flags", p_e_dll_flags, p_e_dll_flags); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_stack_reserve_size", p_e_stack_reserve_size, p_e_stack_reserve_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_stack_commit_size", p_e_stack_commit_size, p_e_stack_commit_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_heap_reserve_size", p_e_heap_reserve_size, p_e_heap_reserve_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_heap_commit_size", p_e_heap_commit_size, p_e_heap_commit_size); fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_loader_flags", p_e_loader_flags, p_e_loader_flags); fprintf(f, "%s%-*s = %u\n", p, w, "e_num_rvasize_pairs", p_e_num_rvasize_pairs); for (unsigned i = 0; i < p_rvasize_pairs->get_pairs().size(); i++) { char p2[256]; int nprint __attribute__((unused)) = snprintf(p2, sizeof p2, "%s.pair[%d].", p, i); assert((size_t)nprint<sizeof p2); w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p2)); fprintf(f, "%s%-*s = rva %s,\tsize 0x%08" PRIx64 " (%" PRIu64 ")\n", p2, w, "..", p_rvasize_pairs->get_pairs()[i]->get_e_rva().to_string().c_str(), p_rvasize_pairs->get_pairs()[i]->get_e_size(), p_rvasize_pairs->get_pairs()[i]->get_e_size()); } if (p_section_table) { fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "section_table", p_section_table->get_id(), p_section_table->get_name()->get_string(true).c_str()); } else { fprintf(f, "%s%-*s = none\n", p, w, "section_table"); } if (variantT() == V_SgAsmPEFileHeader) //unless a base class hexdump(f, 0, std::string(p)+"data at ", p_data); /* Show the simulated loader memory map */ const MemoryMap::Ptr map = get_loader_map(); if (map) { map->dump(f, (std::string(p)+"loader_map: ").c_str()); } else { fprintf(f, "%s%-*s = not defined\n", p, w, "loader_map"); } }
/* Looks at the RVA/Size pairs in the PE header and creates an SgAsmGenericSection object for each one. This must be done * after we build the mapping from virtual addresses to file offsets. */ void SgAsmPEFileHeader::create_table_sections() { /* First, only create the sections. */ for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) { SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i]; if (0==pair->get_e_size()) continue; /* Table names come from PE file specification and are hard coded by RVA/Size pair index */ const char *tabname_short; std::string tabname = rvasize_pair_name((PairPurpose)i, &tabname_short); /* Find the starting offset in the file. * FIXME: We have a potential problem here in that ROSE sections are always contiguous in the file but a section created * from an RVA/Size pair is not necessarily contiguous in the file. Normally such sections are in fact * contiguous and we'll just ignore this for now. In any case, as long as these sections only ever read their * data via the same MemoryMap that we use here, everything should be fine. [RPM 2009-08-17] */ rose_addr_t pair_va = get_base_va() + pair->get_e_rva(); MemoryMap::Ptr map = get_loader_map(); ROSE_ASSERT(map!=NULL); if (!map->baseSize(pair_va, pair->get_e_size()).exists(Sawyer::Container::MATCH_WHOLE)) { mlog[WARN] <<"SgAsmPEFileHeader::create_table_sections: pair-" <<i <<", rva=" <<StringUtility::addrToString(pair->get_e_rva().get_rva()) <<", size=" <<StringUtility::plural(pair->get_e_size(), "bytes") <<" \"" <<StringUtility::cEscape(tabname) <<"\":" <<" unable to find a mapping for the virtual address (skipping)\n"; continue; } const MemoryMap::Node &me = *map->at(pair_va).findNode(); rose_addr_t file_offset = me.value().offset() + pair_va - me.key().least(); /* Create the new section */ SgAsmGenericSection *tabsec = NULL; switch (i) { case 0: { /* Sometimes export sections are represented by a ".edata" section, and sometimes they're represented by an * RVA/Size pair, sometimes both point to the same part of the file, and sometimes the RVA/Size pair points to * a different part of the file. We don't want the exports duplicated in the AST, so we only create this table * as exports if we haven't already seen some other export section. */ SgAsmGenericSectionPtrList §ions = get_sections()->get_sections(); bool seen_exports = false; for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_exports && si!=sections.end(); ++si) seen_exports = isSgAsmPEExportSection(*si); if (seen_exports) { tabsec = new SgAsmGenericSection(get_file(), this); } else { tabsec = new SgAsmPEExportSection(this); } break; } case 1: { /* Sometimes import sections are represented by a ".idata" section, and sometimes they're represented by an * RVA/Size pair, and sometimes both point to the same part of the file. We don't want the imports duplicated * in the AST, so we only create this table as imports if we haven't already seen some other import section. */ SgAsmGenericSectionPtrList §ions = get_sections()->get_sections(); bool seen_imports = false; for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_imports && si!=sections.end(); ++si) seen_imports = isSgAsmPEImportSection(*si); if (seen_imports) { tabsec = new SgAsmGenericSection(get_file(), this); } else { tabsec = new SgAsmPEImportSection(this); } break; } default: { tabsec = new SgAsmGenericSection(get_file(), this); break; } } tabsec->set_name(new SgAsmBasicString(tabname)); tabsec->set_short_name(tabname_short); tabsec->set_synthesized(true); tabsec->set_purpose(SP_HEADER); tabsec->set_offset(file_offset); tabsec->set_size(pair->get_e_size()); tabsec->set_file_alignment(1); tabsec->set_mapped_alignment(1); tabsec->set_mapped_preferred_rva(pair->get_e_rva().get_rva()); tabsec->set_mapped_actual_va(pair->get_e_rva().get_rva()+get_base_va()); /*FIXME: not sure this is correct. [RPM 2009-09-11]*/ tabsec->set_mapped_size(pair->get_e_size()); tabsec->set_mapped_rperm(true); tabsec->set_mapped_wperm(false); tabsec->set_mapped_xperm(false); pair->set_section(tabsec); pair->set_e_rva(pair->get_e_rva().set_section(tabsec)); } /* Now parse the sections */ for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) { SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i]; SgAsmGenericSection *tabsec = pair->get_section(); if (tabsec) tabsec->parse(); } }
std::string readString(rose_addr_t va) const { MemoryMap::Ptr map = ConcreteSemantics::MemoryState::promote(ops_->currentState()->memoryState())->memoryMap(); return map->readString(va, 256 /*arbitrary*/); }