in src/BinaryParsers/ElfBinary/Dwarf/DwarfLineNumberProgram.cs [176:375]
private static List<DwarfFileInformation> ReadData(DwarfMemoryReader debugLine, NormalizeAddressDelegate addressNormalizer)
{
// Read header
ulong length = debugLine.ReadLength(out bool is64bit);
int endPosition = debugLine.Position + (int)length;
if (endPosition > debugLine.Data.Length - 1)
{
endPosition = debugLine.Data.Length - 1;
}
debugLine.ReadUshort(); // version
debugLine.ReadOffset(is64bit); // headerLength
byte minimumInstructionLength = debugLine.ReadByte();
bool defaultIsStatement = debugLine.ReadByte() != 0;
sbyte lineBase = (sbyte)debugLine.ReadByte();
byte lineRange = debugLine.ReadByte();
byte operationCodeBase = debugLine.ReadByte();
if (operationCodeBase <= 0)
{
return new List<DwarfFileInformation>();
}
// Read operation code lengths
uint[] operationCodeLengths = new uint[operationCodeBase];
operationCodeLengths[0] = 0;
for (int i = 1; i < operationCodeLengths.Length && debugLine.Position < endPosition; i++)
{
operationCodeLengths[i] = debugLine.LEB128();
}
// Read directories
List<string> directories = new List<string>();
while (debugLine.Position < endPosition && debugLine.Peek() != 0)
{
string directory = debugLine.ReadString();
directory = directory.Replace('/', Path.DirectorySeparatorChar);
directories.Add(directory);
}
debugLine.ReadByte(); // Skip zero termination byte
// Read files
List<DwarfFileInformation> files = new List<DwarfFileInformation>();
while (debugLine.Position < endPosition && debugLine.Peek() != 0)
{
files.Add(ReadFile(debugLine, directories));
}
debugLine.ReadByte(); // Skip zero termination byte
// Parse lines
ParsingState state = new ParsingState(files.FirstOrDefault(), defaultIsStatement, minimumInstructionLength);
uint lastAddress = 0;
while (debugLine.Position < endPosition)
{
byte operationCode = debugLine.ReadByte();
if (operationCode >= operationCodeLengths.Length)
{
// Special operation code
int adjustedOperationCode = operationCode - operationCodeBase;
int operationAdvance = adjustedOperationCode / lineRange;
state.AdvanceAddress(operationAdvance);
int lineAdvance = lineBase + (adjustedOperationCode % lineRange);
state.Line += (uint)lineAdvance;
state.AddCurrentLineInfo();
state.IsBasicBlock = false;
state.IsPrologueEnd = false;
state.IsEpilogueEnd = false;
state.Discriminator = 0;
}
else
{
switch ((DwarfLineNumberStandardOpcode)operationCode)
{
case DwarfLineNumberStandardOpcode.Extended:
{
uint extendedLength = debugLine.LEB128();
int newPosition = debugLine.Position + (int)extendedLength;
DwarfLineNumberExtendedOpcode extendedCode = DwarfLineNumberExtendedOpcode.Unknown;
if (debugLine.Position + 1 <= debugLine.Data.Length)
{
extendedCode = (DwarfLineNumberExtendedOpcode)debugLine.ReadByte();
}
switch (extendedCode)
{
case DwarfLineNumberExtendedOpcode.EndSequence:
lastAddress = state.Address;
state.IsSequenceEnd = true;
state.AddCurrentLineInfo();
state.Reset(files.FirstOrDefault());
break;
case DwarfLineNumberExtendedOpcode.SetAddress:
{
state.Address = debugLine.ReadUint();
if (state.Address == 0)
{
state.Address = lastAddress;
}
state.OperationIndex = 0;
}
break;
case DwarfLineNumberExtendedOpcode.DefineFile:
state.File = ReadFile(debugLine, directories);
files.Add(state.File);
break;
case DwarfLineNumberExtendedOpcode.SetDiscriminator:
state.Discriminator = debugLine.LEB128();
break;
default:
break;
}
debugLine.Position = newPosition;
}
break;
case DwarfLineNumberStandardOpcode.Copy:
state.AddCurrentLineInfo();
state.IsBasicBlock = false;
state.IsPrologueEnd = false;
state.IsEpilogueEnd = false;
state.Discriminator = 0;
break;
case DwarfLineNumberStandardOpcode.AdvancePc:
state.AdvanceAddress((int)debugLine.LEB128());
break;
case DwarfLineNumberStandardOpcode.AdvanceLine:
state.Line += debugLine.SLEB128();
break;
case DwarfLineNumberStandardOpcode.SetFile:
int index = (int)debugLine.LEB128() - 1;
if (index >= 0 && index < files.Count)
{
state.File = files[index];
}
break;
case DwarfLineNumberStandardOpcode.SetColumn:
state.Column = debugLine.LEB128();
break;
case DwarfLineNumberStandardOpcode.NegateStmt:
state.IsStatement = !state.IsStatement;
break;
case DwarfLineNumberStandardOpcode.SetBasicBlock:
state.IsBasicBlock = true;
break;
case DwarfLineNumberStandardOpcode.ConstAddPc:
state.AdvanceAddress((255 - operationCodeBase) / lineRange);
break;
case DwarfLineNumberStandardOpcode.FixedAdvancePc:
state.Address += debugLine.ReadUshort();
state.OperationIndex = 0;
break;
case DwarfLineNumberStandardOpcode.SetPrologueEnd:
state.IsPrologueEnd = true;
break;
case DwarfLineNumberStandardOpcode.SetEpilogueBegin:
state.IsEpilogueEnd = true;
break;
case DwarfLineNumberStandardOpcode.SetIsa:
state.Isa = debugLine.LEB128();
break;
default:
// Special opcodes(13 or greater)
break;
}
}
}
// Fix lines in files...
foreach (DwarfFileInformation file in files)
{
for (int i = 0; i < file.Lines.Count; i++)
{
file.Lines[i].Address = (uint)addressNormalizer(file.Lines[i].Address);
}
}
return files;
}