/// <summary> /// Fetches the source location (line number and file), given the relative virtual address (RVA) /// of the location in the executable. /// </summary> public SourceLocation SourceLocationForRva(uint rva) { m_reader.m_log.WriteLine("SourceLocationForRva: looking up RVA {0:x} ", rva); uint fetchCount; IDiaEnumLineNumbers sourceLocs; m_session.findLinesByRVA(rva, 0, out sourceLocs); IDiaLineNumber sourceLoc; sourceLocs.Next(1, out sourceLoc, out fetchCount); if (fetchCount == 0) { m_reader.m_log.WriteLine("SourceLocationForRva: No lines for RVA {0:x} ", rva); return null; } var buildTimeSourcePath = sourceLoc.sourceFile.fileName; var lineNum = (int)sourceLoc.lineNumber; var sourceFile = new SourceFile(this, sourceLoc.sourceFile); var sourceLocation = new SourceLocation(sourceFile, (int)sourceLoc.lineNumber); return sourceLocation; }
/// <summary> /// Managed code is shipped as IL, so RVA to NATIVE mapping can't be placed in the PDB. Instead /// what is placed in the PDB is a mapping from a method's meta-data token and IL offset to source /// line number. Thus if you have a metadata token and IL offset, you can again get a source location /// </summary> public SourceLocation SourceLocationForManagedCode(uint methodMetaDataToken, int ilOffset) { m_reader.m_log.WriteLine("SourceLocationForManagedCode: Looking up method token {0:x} ilOffset {1:x}", methodMetaDataToken, ilOffset); IDiaSymbol methodSym; m_session.findSymbolByToken(methodMetaDataToken, SymTagEnum.SymTagFunction, out methodSym); if (methodSym == null) { m_reader.m_log.WriteLine("SourceLocationForManagedCode: No symbol for token {0:x} ilOffset {1:x}", methodMetaDataToken, ilOffset); return null; } uint fetchCount; IDiaEnumLineNumbers sourceLocs; IDiaLineNumber sourceLoc; // TODO FIX NOW, this code here is for debugging only turn if off when we are happy. m_session.findLinesByRVA(methodSym.relativeVirtualAddress, (uint)(ilOffset + 256), out sourceLocs); for (int i = 0; ;i++) { sourceLocs.Next(1, out sourceLoc, out fetchCount); if (fetchCount == 0) break; if (i == 0) m_reader.m_log.WriteLine("SourceLocationForManagedCode: source file: {0}", sourceLoc.sourceFile.fileName); m_reader.m_log.WriteLine("SourceLocationForManagedCode: ILOffset {0:x} -> line {1}", sourceLoc.relativeVirtualAddress - methodSym.relativeVirtualAddress, sourceLoc.lineNumber); } // End TODO FIX NOW debugging code // For managed code, the 'RVA' is a 'cumulative IL offset' (amount of IL bytes before this in the module) // Thus you find the line number of a particular IL offset by adding the offset within the method to // the cumulative IL offset of the start of the method. m_session.findLinesByRVA(methodSym.relativeVirtualAddress + (uint)ilOffset, 256, out sourceLocs); sourceLocs.Next(1, out sourceLoc, out fetchCount); if (fetchCount == 0) { m_reader.m_log.WriteLine("SourceLocationForManagedCode: No lines for token {0:x} ilOffset {1:x}", methodMetaDataToken, ilOffset); return null; } var sourceFile = new SourceFile(this, sourceLoc.sourceFile); int lineNum; // FEEFEE is some sort of illegal line number that is returned some time, It is better to ignore it. // and take the next valid line for(;;) { lineNum = (int)sourceLoc.lineNumber; if (lineNum != 0xFEEFEE) break; sourceLocs.Next(1, out sourceLoc, out fetchCount); if (fetchCount == 0) break; } var sourceLocation = new SourceLocation(sourceFile, lineNum); return sourceLocation; }