/** * Get the statement at a specific label. If there is no statement stored, attempts to disassemble * the instruction at the label's virtual address. If the address is outside of the file area, * logs an error and returns a Halt statement by default. * * @param label The label for which to get the statement * @return The statement object at label. */ public final RTLStatement getStatement(RTLLabel label) { if (!statementMap.containsKey(label)) { AbsoluteAddress address = label.getAddress(); Instruction instr = getInstruction(address); // If we did not get an instruction, add an artificial Halt for recovery if (instr == null) { RTLHalt halt = new RTLHalt(); halt.setLabel(label); putStatement(halt); logger.error("ERROR: Replacing unknown instruction with HALT."); if (Options.debug.getValue()) throw new DisassemblyException("Disassembly failed at " + address); } else { try { StatementSequence seq = arch.getRTLEquivalent(address, instr); for (RTLStatement s : seq) { putStatement(s); } } catch (Exception e) { logger.error("Error during translation of instruction to IL"); e.printStackTrace(); RTLStatement skip = new RTLSkip(); skip.setLabel(label); skip.setNextLabel(new RTLLabel(new AbsoluteAddress(address.getValue() + 1))); putStatement(skip); } assert statementMap.containsKey(label) : "Disassembly did not produce label: " + label; } } return statementMap.get(label); }
/** * Stores a statement in the program. If a statement already exists with the same label, it is * replaced. * * @param stmt The statement to be stored. Has to contain a proper label. */ public final void putStatement(RTLStatement stmt) { RTLStatement existing = statementMap.get(stmt.getLabel()); if (existing != null) { if (existing.equals(stmt)) return; logger.debug("Replacing statement at " + stmt.getLabel()); } statementMap.put(stmt.getLabel(), stmt); }
/** * Returns the address of the given procedure within the given library. Procedures present within * the analyzed modules are given precedence over stub functions. * * @param library * @param procedure * @return the virtual address of the procedure */ public AbsoluteAddress getProcAddress(String library, String procedure) { ExportedSymbol expSymbol = exportedSymbols.get(procedure); if (expSymbol != null) { return expSymbol.getAddress(); } else { return stubLibrary.resolveSymbol(library, procedure); } }
/** Resolves symbols between the loaded modules. */ private void resolveSymbols() { Iterator<UnresolvedSymbol> sIter = unresolvedSymbols.iterator(); while (sIter.hasNext()) { UnresolvedSymbol unresolvedSymbol = sIter.next(); ExportedSymbol symbol = exportedSymbols.get(removeDecoration(unresolvedSymbol.getName())); if (symbol != null) { logger.debug("Resolving symbol " + unresolvedSymbol.getName()); unresolvedSymbol.resolve(symbol.getAddress()); sIter.remove(); } } }
/** * Gets the assembly instruction at the specified virtual address. * * @param address a virtual address * @return the assembly instruction at the specified address */ public final Instruction getInstruction(AbsoluteAddress address) { Instruction instr = assemblyMap.get(address); if (instr != null) { return instr; } else { // No real instructions in prologue/epilogue if (harness.contains(address) || isStub(address)) return null; ExecutableImage module = getModule(address); long fp = -1; if (module == null) { logger.error("No module for address " + address + ". Cannot disassemble instruction!"); } else { fp = module.getFilePointer(address); // Also check whether fp is out of the int range, since the X86Disassembler actually // performs this cast in its implementation. if (fp < 0 || (int) fp < 0) { logger.error("Requested instruction outside of file area: " + address); } else { if (!module.isCodeArea(address)) { logger.error("Requested instruction outside code section: " + address); return null; } instr = module.getDisassembler().decodeInstruction(fp); if (instr == null) { logger.error("Instruction could not be disassembled at: " + address); } } } if (instr != null) putInstruction(address, instr); return instr; } }