public static IEnumerable <InstructionData> GenerateInstructionData(ReverseSymbolTable symTable, TextSegmentAccessor textSegment, SourceDebugData dbgData) { IEnumerable <InstructionData> ret = null; if (File.Exists(dbgData.SourceFilePath)) { try { ret = GenerateInstructionDataWithSource(symTable, textSegment, dbgData); } catch (Exception) { // if anything goes wrong, try just parsing the file with no source. ret = GenerateInstructionDataWithNoSource(symTable, textSegment); } } else { ret = GenerateInstructionDataWithNoSource(symTable, textSegment); } return(ret); }
/// <summary> /// Parses a .JEF file for all relevent assembly data. /// </summary> /// <param name="fileName">The path of the file to parse.</param> /// <returns>A structure representing all the relevant data in the file.</returns> public static JefFile ParseFile(string fileName) { using (var fileReader = new EndianReader(File.OpenRead(fileName), Endianness.LittleEndian)) { FileHeader hdr = ReadHeader(fileReader); System.Diagnostics.Debug.Assert(fileReader.BaseStream.Position == 0x30); int dataMdataSize = hdr.DataOffset - hdr.DataMetadataOffset; IEnumerable <MetadataElement> dataMetaData = ReadMetadataSection(fileReader, dataMdataSize); int dataSize = hdr.TextOffset - hdr.DataOffset; IEnumerable <byte> dataElems = ParseDataSegment(fileReader, dataMetaData); int textSize = hdr.ExternOffset - hdr.TextOffset; IEnumerable <int> textElems = ParseTextSection(fileReader, textSize); // extern segment should just be all zeroes, so read the number of bytes as specified in the size. int externSize = hdr.SymTblOffset - hdr.ExternOffset; IEnumerable <byte> externElems = fileReader.ReadBytes(externSize); int symTblSize = hdr.SrcMapOffset - hdr.SymTblOffset; ReverseSymbolTable symTbl = ParseSymbolTableSection(fileReader, symTblSize); // src map table runs from the starting offset to the end of the file, so just calculate the delta. int srcMapSize = (int)(fileReader.BaseStream.Length - hdr.SrcMapOffset); SourceDebugData dbgData = ParseSourceMapInformation(fileReader, srcMapSize); return(new JefFile(hdr.BaseDataAddress, hdr.BaseTextAddress, hdr.BaseExternAddress, dataMetaData, dataElems, textElems, externElems, symTbl, dbgData)); } }
public DisassembledJefFile(DataSegmentAccessor dataSegment, TextSegmentAccessor instructions, IEnumerable <byte> externSegment, ReverseSymbolTable symTable, IEnumerable <MetadataElement> metadata, SourceDebugData dbgData) : base(dataSegment, instructions, externSegment, symTable, dbgData) { m_FileWriter = new JefAssemblyFileWriter(this); m_Metadata = metadata; }
/// <summary> /// Creates an instance of the disassembled file. /// </summary> /// <param name="dataSegment">The disassembled .data segment of the file.</param> /// <param name="instructions">The disassembled .text segment of the file.</param> /// <param name="externSegment">The constituent bytes of the .extern segment.</param> /// <param name="symTable">The symbol table associated with the file.</param> /// <param name="dbgData">The source file information associated with the file.</param> protected DisassembledFileBase(DataSegmentAccessor dataSegment, TextSegmentAccessor instructions, IEnumerable <byte> externSegment, ReverseSymbolTable symTable, SourceDebugData dbgData) { m_DataSegment = dataSegment; m_TextSegment = instructions; m_ExternSize = externSegment.Count(); m_SymTbl = symTable; m_DbgInfo = dbgData; }
/// <summary> /// Creates a representation of a .JEF file in memory. /// </summary> /// <param name="baseDataAddress">The base .data segment address.</param> /// <param name="baseTextAddress">The base .text segment address.</param> /// <param name="baseExternAddress">The base .extern segment address.</param> /// <param name="metadataElems">An IEnumerable of all the data metadata elements.</param> /// <param name="dataElements">An IEnumerable of all the data elements, represented as bytes.</param> /// <param name="textElements">An IEnumerable of all 32-bit instructions in the .JEF file.</param> /// <param name="externElements">An IEnumerable of all the .extern elements in the .JEF file.</param> /// <param name="symTable">A reconstructed SymbolTable instance from the .JEF file.</param> private JefFile(int baseDataAddress, int baseTextAddress, int baseExternAddress, IEnumerable <MetadataElement> metadataElems, IEnumerable <byte> dataElements, IEnumerable <int> textElements, IEnumerable <byte> externElements, ReverseSymbolTable symTable, SourceDebugData dbgData) { m_BaseDataAddress = baseDataAddress; m_BaseTextAddress = baseTextAddress; m_BaseExternAddress = baseExternAddress; m_DataMetadata = metadataElems; m_DataElems = dataElements; m_TextElems = textElements; m_ExternElems = externElements; m_SymTbl = symTable; m_DbgData = dbgData; }
/// <summary> /// Parses the symtbl segment of the file, and reconstructs a reverse lookup symbol table. /// </summary> /// <param name="reader">The reader to parse the file with.</param> /// <param name="sectionSize">The size of the symbol table area, in bytes.</param> /// <returns>A populated symbol reverse lookup table.</returns> private static ReverseSymbolTable ParseSymbolTableSection(BinaryReader reader, int sectionSize) { // for every symbol, read the first byte. this dictates how long the symbol name is. var symTable = new ReverseSymbolTable(); int readBytes = 0; while (readBytes < sectionSize) { byte symStrSize = reader.ReadByte(); ++readBytes; byte[] symbolName = reader.ReadBytes(symStrSize); readBytes += symStrSize; string symNameStr = Encoding.ASCII.GetString(symbolName); int symbolAddress = reader.ReadInt32(); readBytes += sizeof(int); symTable.AddSymbol(symbolAddress, new Symbol(symNameStr, SegmentType.Data, symbolAddress)); } return(symTable); }
/// <summary> /// Formats and stringifies an instruction as well as its parameters. /// </summary> /// <param name="currPgrmCtr">The value that the program counter would theoretically be at /// upon encountering this instruction.</param> /// <param name="inst">The disassembled instruction to stringify.</param> /// <param name="symTable">A reverse symbol table used to map addresses back to label names.</param> /// <returns>A string representing the instruction and its parameters that can be written to a text file.</returns> public string GetFormattedInstruction(int currPgrmCtr, DisassembledInstruction inst, ReverseSymbolTable symTable) { string retStr = string.Empty; // first, see if the program counter has a symbol mapped to it. if (symTable.ContainsSymbol(currPgrmCtr)) { Symbol sym = symTable.GetSymbol(currPgrmCtr); retStr += sym.LabelName + ":\t\t"; } else { retStr += "\t\t\t"; } retStr += m_Name; return(retStr); }
/// <summary> /// Formats and stringifies an instruction as well as its parameters. /// </summary> /// <param name="currPgrmCtr">The value that the program counter would theoretically be at /// upon encountering this instruction.</param> /// <param name="inst">The disassembled instruction to stringify.</param> /// <param name="symTable">A reverse symbol table used to map addresses back to label names.</param> /// <returns>A string representing the instruction and its parameters that can be written to a text file.</returns> public string GetFormattedInstruction(int currPgrmCtr, DisassembledInstruction inst, ReverseSymbolTable symTable) { string retStr = string.Empty; // first, see if the program counter has a symbol mapped to it. if (symTable.ContainsSymbol(currPgrmCtr)) { Symbol sym = symTable.GetSymbol(currPgrmCtr); retStr += sym.LabelName + ":\t\t"; } else { retStr += "\t\t\t"; } retStr += "flw "; if (inst.Parameters.Count() != 3) { throw new ArgumentException("Floating point I instruction expected 3 arguments, received " + inst.Parameters.Count()); } string rd = ReverseRegisterMap.GetStringifiedFloatingPtRegisterValue(inst.Parameters.ElementAt(0)); string rs1 = ReverseRegisterMap.GetStringifiedRegisterValue(inst.Parameters.ElementAt(1)); int offset = inst.Parameters.ElementAt(2); retStr += rd + ", " + offset + "(" + rs1 + ")"; return(retStr); }
/// <summary> /// Writes out the .data segment of the file. /// </summary> /// <param name="writer">The StreamWriter to use while writing the file.</param> /// <param name="symTable">The reverse lookup symbol table to use for symbol mapping.</param> /// <param name="dataSegment">The accessor to the file's data segment.</param> private void GenerateDataSegment(StreamWriter writer, ReverseSymbolTable symTable, DataSegmentAccessor dataSegment) { int currAlignment = CommonConstants.DEFAULT_ALIGNMENT; writer.WriteLine(".data"); int processedByteCount = 0; int currAddress = dataSegment.BaseRuntimeDataAddress; foreach (MetadataElement elem in m_File.Metadata) { // don't do any processing if we're looking at padding bytes. if (processedByteCount % currAlignment == 0) { // first, see if there's a label associated with the data element. if (symTable.ContainsSymbol(currAddress)) { // if so, write it out. Symbol sym = symTable.GetSymbol(currAddress); writer.Write(sym.LabelName); writer.Write(":\t\t"); } else { writer.Write("\t\t\t"); } // determine what to write out. switch (elem.TypeCode) { case ObjectTypeCode.Byte: { writer.Write(".byte "); byte value = dataSegment.ReadUnsignedByte(currAddress); writer.WriteLine(value); processedByteCount += sizeof(byte); break; } case ObjectTypeCode.Half: { writer.Write(".half "); short value = dataSegment.ReadShort(currAddress); writer.WriteLine(value); processedByteCount += sizeof(short); break; } case ObjectTypeCode.Word: { writer.Write(".word "); int value = dataSegment.ReadWord(currAddress); writer.WriteLine(value); processedByteCount += sizeof(int); break; } case ObjectTypeCode.Dword: { writer.Write(".dword "); long value = dataSegment.ReadLong(currAddress); writer.WriteLine(value); processedByteCount += sizeof(long); break; } case ObjectTypeCode.String: { writer.Write(".asciiz "); string value = dataSegment.ReadString(currAddress); string processedValue = ProcessString(value); writer.WriteLine(processedValue); processedByteCount += value.Length; // account for a null terminating byte here. ++processedByteCount; break; } case ObjectTypeCode.AlignmentChange: { currAlignment = elem.Alignment; break; } } } else { // otherwise, assume we're at a padding byte and don't print it. ++processedByteCount; } currAddress += elem.Size; } }
/// <summary> /// Writes out the .data segment of the file. /// </summary> /// <param name="writer">The StreamWriter to use while writing the file.</param> /// <param name="symTable">The reverse lookup symbol table to use for symbol mapping.</param> /// <param name="dataSegment">The accessor to the file's data segment.</param> private void GenerateDataSegment(StreamWriter writer, ReverseSymbolTable symTable, DataSegmentAccessor dataSegment) { int currAddress = dataSegment.BaseRuntimeDataAddress; writer.WriteLine(".data"); int endAddress = currAddress + dataSegment.SegmentSize; // get the address of each symbol in the .data segment, and sort // them in ascending order. var symbolAddresses = symTable.AllSymbols .SelectIf(sym => sym.Address, sym => dataSegment.BaseRuntimeDataAddress <= sym.Address && sym.Address < endAddress) .OrderBy(num => num); while (currAddress < endAddress) { // are there any addresses in our symbol table that fall between our current // address and the next address we'll examine? if (symbolAddresses.Any(address => currAddress <= address && address < (currAddress + sizeof(int)))) { // okay, slightly narrow our screen if (symbolAddresses.Any(address => currAddress <= address && address < (currAddress + sizeof(short)))) { if (symTable.ContainsSymbol(currAddress)) { Symbol sym = symTable.GetSymbol(currAddress); writer.Write(sym.LabelName); writer.Write(":\t\t"); switch (sym.Size) { case sizeof(byte): { writer.Write(".byte "); sbyte value = dataSegment.ReadSignedByte(currAddress); writer.WriteLine(value.ToString(StringifyAsHexadecimal(value, 2))); currAddress += sizeof(byte); break; } case sizeof(short): { writer.Write(".half "); short value = dataSegment.ReadShort(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 4)); currAddress += sizeof(short); break; } case sizeof(int): { writer.Write(".word "); int value = dataSegment.ReadWord(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 8)); currAddress += sizeof(int); break; } case sizeof(long): { writer.Write(".dword "); long value = dataSegment.ReadLong(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 16)); currAddress += sizeof(int); break; } default: { // just be cheap for now and write out numeric values // (even though this could be an ascii string, in theory). // maybe at some point the assembler will be nice enough // to force strings into .strtable section for smarter // heuristics, but we don't want to force that upon the user // unless the user specifically directs us so. // (or maybe we do?). if someone thinks of a better // algorithm that can be done in the disassembler, I'm // al ears. int numWordsInSize = sym.Size / sizeof(int); int numLeftover = sym.Size % sizeof(int); int numHalfWordsInRemainingBytes = numLeftover / sizeof(int); int numRemainingBytes = numLeftover % sizeof(int); for (int i = 0; i < numWordsInSize; ++i) { writer.Write(".word "); int value = dataSegment.ReadWord(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 8)); currAddress += sizeof(int); } for (int i = 0; i < numHalfWordsInRemainingBytes; ++i) { writer.Write(".half "); short value = dataSegment.ReadShort(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 4)); currAddress += sizeof(short); } for (int i = 0; i < numRemainingBytes; ++i) { writer.Write(".byte "); sbyte value = dataSegment.ReadSignedByte(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 2)); currAddress += sizeof(byte); } break; } // todo: determine if we need to perform alignment // detection (as in theory at this point we could judge // if the new byte offset is on a word boundary). } } else { writer.Write(".byte "); sbyte value = dataSegment.ReadSignedByte(currAddress); writer.WriteLine(value.ToString(StringifyAsHexadecimal(value, 2))); currAddress += sizeof(byte); break; } } else { writer.Write(".half "); short value = dataSegment.ReadShort(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 4)); currAddress += sizeof(short); } } else { writer.Write(".word "); int value = dataSegment.ReadWord(currAddress); writer.WriteLine(StringifyAsHexadecimal(value, 8)); currAddress += sizeof(int); } } }
/// <summary> /// Formats and stringifies an instruction as well as its parameters. /// </summary> /// <param name="currPgrmCtr">The value that the program counter would theoretically be at /// upon encountering this instruction.</param> /// <param name="inst">The disassembled instruction to stringify.</param> /// <param name="symTable">A reverse symbol table used to map addresses back to label names.</param> /// <returns>A string representing the instruction and its parameters that can be written to a text file.</returns> public string GetFormattedInstruction(int currPgrmCtr, DisassembledInstruction inst, ReverseSymbolTable symTable) { string retStr = string.Empty; // first, see if the program counter has a symbol mapped to it. if (symTable.ContainsSymbol(currPgrmCtr)) { Symbol sym = symTable.GetSymbol(currPgrmCtr); retStr += sym.LabelName + ":\t\t"; } else { retStr += "\t\t\t"; } retStr += m_Name + ' '; if (inst.Parameters.Count() != 2) { throw new ArgumentException("U-type instruction expected 2 arguments, received " + inst.Parameters.Count()); } string rd = ReverseRegisterMap.GetStringifiedRegisterValue(inst.Parameters.ElementAt(0)); int immediate = inst.Parameters.ElementAt(1); retStr += rd + ", 0x" + immediate.ToString("X2"); return(retStr); }
/// <summary> /// Formats and stringifies an instruction as well as its parameters. /// </summary> /// <param name="currPgrmCtr">The value that the program counter would theoretically be at /// upon encountering this instruction.</param> /// <param name="inst">The disassembled instruction to stringify.</param> /// <param name="symTable">A reverse symbol table used to map addresses back to label names.</param> /// <returns>A string representing the instruction and its parameters that can be written to a text file.</returns> public string GetFormattedInstruction(int currPgrmCtr, DisassembledInstruction inst, ReverseSymbolTable symTable) { string retStr = string.Empty; // first, see if the program counter has a symbol mapped to it. if (symTable.ContainsSymbol(currPgrmCtr)) { Symbol sym = symTable.GetSymbol(currPgrmCtr); retStr += sym.LabelName + ":\t\t"; } else { retStr += "\t\t\t"; } retStr += m_Name + ' '; if (inst.Parameters.Count() != 3) { throw new ArgumentException("sb instruction expected 3 arguments, received " + inst.Parameters.Count()); } string rs1 = ReverseRegisterMap.GetStringifiedRegisterValue(inst.Parameters.ElementAt(0)); string rs2 = ReverseRegisterMap.GetStringifiedRegisterValue(inst.Parameters.ElementAt(1)); retStr += rs1 + ", " + rs2 + ", "; int offset = inst.Parameters.ElementAt(2); int address = currPgrmCtr + offset; // see if there's a symbol mapped to it. if (symTable.ContainsSymbol(address)) { Symbol sym = symTable.GetSymbol(address); retStr += sym.LabelName; } else { retStr += "0x" + address.ToString("X2"); } return(retStr); }
public DisassembledElfFile(DataSegmentAccessor dataSegment, TextSegmentAccessor instructions, IEnumerable <byte> externSegment, ReverseSymbolTable symTable) : base(dataSegment, instructions, externSegment, symTable, new SourceDebugData(string.Empty)) { m_FileWriter = new ElfAssemblyFileWriter(this); }
private static IEnumerable <InstructionData> GenerateInstructionDataWithNoSource(ReverseSymbolTable symTable, TextSegmentAccessor textSegment) { var instructions = new List <InstructionData>(); int currPgrmCtr = textSegment.StartingSegmentAddress; foreach (DisassembledInstruction inst in textSegment.RawInstructions) { IParameterStringifier stringifier = InstructionTextMap.GetParameterStringifier(inst.InstructionType); string formattedInstruction = stringifier.GetFormattedInstruction(currPgrmCtr, inst, symTable); var srcLineInfo = new SourceLineInformation(string.Empty, -1, currPgrmCtr); var instructionElem = new InstructionData(inst.InstructionWord, currPgrmCtr, formattedInstruction, srcLineInfo); instructions.Add(instructionElem); currPgrmCtr += sizeof(int); } return(instructions); }
private static IEnumerable <InstructionData> GenerateInstructionDataWithSource(ReverseSymbolTable symTable, TextSegmentAccessor textSegment, SourceDebugData dbgData) { var instructions = new List <InstructionData>(); using (var reader = File.OpenText(dbgData.SourceFilePath)) { int currPgrmCtr = textSegment.StartingSegmentAddress; foreach (DisassembledInstruction inst in textSegment.RawInstructions) { IParameterStringifier stringifier = InstructionTextMap.GetParameterStringifier(inst.InstructionType); string formattedInstruction = stringifier.GetFormattedInstruction(currPgrmCtr, inst, symTable); string originalSourceLine = string.Empty; int lineNum = -1; if (dbgData.IsSourceTextAssociatedWithAddress(currPgrmCtr)) { lineNum = dbgData.GetLineNumberAssociatedWithAddress(currPgrmCtr); originalSourceLine = reader.ReadLineAt(lineNum); originalSourceLine = originalSourceLine.Trim(); } var srcLineInfo = new SourceLineInformation(dbgData.SourceFilePath, lineNum, currPgrmCtr, originalSourceLine); var instructionElem = new InstructionData(inst.InstructionWord, currPgrmCtr, formattedInstruction, srcLineInfo); instructions.Add(instructionElem); currPgrmCtr += sizeof(int); } return(instructions); } }