123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- dwline.c
- Abstract:
- This module implements support for processing the DWARF 2+ line number
- program.
- Author:
- Evan Green 8-Dec-2015
- Environment:
- Debug
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <minoca/lib/status.h>
- #include <minoca/lib/im.h>
- #include "dwarfp.h"
- #include <assert.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define DWARF_LINE_IS_STATEMENT 0x00000001
- #define DWARF_LINE_BASIC_BLOCK 0x00000002
- #define DWARF_LINE_END_SEQUENCE 0x00000004
- #define DWARF_LINE_PROLOGUE_END 0x00000008
- #define DWARF_LINE_EPILOGUE_BEGIN 0x00000010
- #define DWARF_INITIAL_INCLUDE_FILE_CAPACITY 4
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- /*++
- Structure Description:
- This structure stores the state of a row in the DWARF line number matrix.
- Members:
- Address - Stores the current address.
- OpIndex - Stores the operation index for Very Long Instruction Word
- instructions. For most architectures this is always zero.
- File - Stores the file index.
- Line - Stores the one-based line number.
- Column - Stores the column number.
- Flags - Stores the bitfield of flags. See DWARF_LINE_* definitions.
- Isa - Stores the instruction set identifier. Zero indicates the
- architecturally defined instruction set.
- Discriminator - Stores the discriminator for multiple blocks that share the
- same file, line, and column. Most of the time this is zero.
- --*/
- typedef struct _DWARF_LINE {
- ULONGLONG Address;
- ULONG OpIndex;
- ULONG File;
- ULONG Line;
- ULONG Column;
- ULONG Flags;
- ULONG Isa;
- ULONG Discriminator;
- } DWARF_LINE, *PDWARF_LINE;
- /*++
- Structure Description:
- This structure stores the state machine context for a DWARF line number
- program.
- Members:
- Registers - Stores the line registers.
- PreviousLine - Stores the previously emitted line number.
- --*/
- typedef struct _DWARF_LINE_STATE {
- DWARF_LINE Registers;
- PSOURCE_LINE_SYMBOL PreviousLine;
- } DWARF_LINE_STATE, *PDWARF_LINE_STATE;
- /*++
- Structure Description:
- This structure stores the information for a source file in the DWARF line
- number program.
- Members:
- Path - Stores a pointer to a string containing the relative or absolute
- path to the file.
- DirectoryIndex - Stores the index of the include directory this file lives
- in.
- ModificationDate - Stores the modification date of the file when it was
- read by the compiler.
- FileSize - Stores the size of the file when it was read by the compiler.
- FileSymbol - Stores a cached pointer to the source file symbol.
- --*/
- typedef struct _DWARF_LINE_FILE {
- PSTR Path;
- DWARF_LEB128 DirectoryIndex;
- DWARF_LEB128 ModificationDate;
- DWARF_LEB128 FileSize;
- PSOURCE_FILE_SYMBOL FileSymbol;
- } DWARF_LINE_FILE, *PDWARF_LINE_FILE;
- /*++
- Structure Description:
- This structure stores the header of a line table program.
- Members:
- UnitLength - Stores the size in bytes of the line number information for
- this compilation unit, not including this field.
- Is64Bit - Stores a boolean indicating whether this table is 64-bit or not.
- Version - Stores the table version number.
- HeaderLength - Stores the number of bytes following the header length
- field to the beginning of the first byte of the line number program
- itself. This is 4/8 bytes depending on whether 64-bit mode is in effect.
- MinimumInstructionLength - Stores the size in bytes of the smallest target
- machine instruction. Line number program opcodes that alter the address
- and op-index registers use this and the maximum operations per
- instruction member in their calculations.
- MaximumOperationsPerInstruction - Stores the maximum number of individual
- operations that may be encoded in an instruction. For non-VLIW
- architectures, this is 1, and the operation pointer is always the
- address register.
- DefaultIsStatement - Stores a boolean indicating the initial value of the
- is-statement flag.
- LineBase - Stores a parameter used in calculating the effects of special
- offsets.
- LineRange - Stores another parameter used in calculating the effects of
- special offsets.
- OpcodeBase - Stores the number assigned to the first special opcode (one
- higher than the highest standard opcode implemented).
- StandardOpcodeLengths - Stores the number of LEB128 operands for each of
- the standard opcodes. The first element of the array corresponds to
- opcode 1, and the last element corresponds to OpcodeBase - 1.
- IncludeDirectories - Stores an array of include paths that the compiler
- searched when generating this compilation unit.
- IncludeDirectoryCount - Stores the number of elements in the include
- directories array, including the space left for the zeroth entry.
- Files - Stores an array of include files.
- FileCount - Stores the number of elements in the files array.
- ProgramStart - Stores a pointer to the start of the line number program.
- End - Stores the end of this table.
- --*/
- typedef struct _DWARF_LINE_TABLE_HEADER {
- ULONGLONG UnitLength;
- BOOL Is64Bit;
- USHORT Version;
- ULONGLONG HeaderLength;
- UCHAR MinimumInstructionLength;
- UCHAR MaximumOperationsPerInstruction;
- UCHAR DefaultIsStatement;
- CHAR LineBase;
- UCHAR LineRange;
- UCHAR OpcodeBase;
- UCHAR StandardOpcodeLengths[32];
- PSTR *IncludeDirectories;
- UINTN IncludeDirectoryCount;
- PDWARF_LINE_FILE Files;
- UINTN FileCount;
- PUCHAR ProgramStart;
- PUCHAR End;
- } DWARF_LINE_TABLE_HEADER, *PDWARF_LINE_TABLE_HEADER;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- INT
- DwarfpProcessLineTable (
- PDWARF_CONTEXT Context,
- PSTR CompileDirectory,
- ULONG AddressSize,
- PUCHAR *Table,
- PUCHAR End
- );
- INT
- DwarfpEmitLine (
- PDWARF_CONTEXT Context,
- PDWARF_LINE_TABLE_HEADER Header,
- PDWARF_LINE_STATE State
- );
- INT
- DwarfpReadLineNumberHeader (
- PUCHAR *Table,
- PUCHAR End,
- PDWARF_LINE_TABLE_HEADER Header
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PSTR DwarfLineStandardOpNames[] = {
- "DwarfLnsCopy",
- "DwarfLnsAdvancePc",
- "DwarfLnsAdvanceLine",
- "DwarfLnsSetFile",
- "DwarfLnsSetColumn",
- "DwarfLnsNegateStatement",
- "DwarfLnsSetBasicBlock",
- "DwarfLnsConstAddPc",
- "DwarfLnsFixedAdvancePc",
- "DwarfLnsSetPrologueEnd",
- "DwarfLnsSetEpilogueBegin",
- "DwarfLnsSetIsa"
- };
- PSTR DwarfLineExtendedOpNames[] = {
- "DwarfLneEndSequence",
- "DwarfLneSetAddress",
- "DwarfLneDefineFile",
- "DwarfLneSetDiscriminator",
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- DwarfpProcessStatementList (
- PDWARF_CONTEXT Context,
- PDWARF_DIE Die
- )
- /*++
- Routine Description:
- This routine is called on a compile unit DIE to process the line numbers.
- Arguments:
- Context - Supplies a pointer to the DWARF context.
- Die - Supplies a pointer to the compile unit DIE.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- PSTR CompileDirectory;
- PUCHAR End;
- PDWARF_LOADING_CONTEXT LoadingContext;
- ULONGLONG Offset;
- PDWARF_ATTRIBUTE_VALUE OffsetAttribute;
- INT Status;
- PUCHAR Table;
- PDWARF_COMPILATION_UNIT Unit;
- assert(Die->Tag == DwarfTagCompileUnit);
- LoadingContext = Context->LoadingContext;
- Unit = LoadingContext->CurrentUnit;
- CompileDirectory = DwarfpGetStringAttribute(Die, DwarfAtCompDir);
- OffsetAttribute = DwarfpGetAttribute(Die, DwarfAtStatementList);
- if (OffsetAttribute == NULL) {
- return 0;
- }
- if (!DWARF_SECTION_OFFSET_FORM(OffsetAttribute->Form, Unit)) {
- return 0;
- }
- Offset = OffsetAttribute->Value.Offset;
- Table = Context->Sections.Lines.Data;
- End = Table + Context->Sections.Lines.Size;
- if ((Table == NULL) || (Table == End) || (Table + Offset >= End)) {
- DWARF_ERROR("DWARF: Missing line number information.\n");
- return 0;
- }
- Table += Offset;
- Status = DwarfpProcessLineTable(Context,
- CompileDirectory,
- Unit->AddressSize,
- &Table,
- End);
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- INT
- DwarfpProcessLineTable (
- PDWARF_CONTEXT Context,
- PSTR CompileDirectory,
- ULONG AddressSize,
- PUCHAR *Table,
- PUCHAR End
- )
- /*++
- Routine Description:
- This routine processes a single compilation unit's DWARF line table.
- Arguments:
- Context - Supplies a pointer to the DWARF context.
- CompileDirectory - Supplies a pointer to the compilation unit's directory.
- AddressSize - Supplies the size of an address on the target.
- Table - Supplies a pointer that on input contains a pointer to the start of
- the section. On output this pointer will be advanced past the fields
- scanned.
- End - Supplies a pointer to the end of the section.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- UINTN AllocationSize;
- PDWARF_LINE_FILE File;
- DWARF_LINE_TABLE_HEADER Header;
- UINTN Index;
- ULONG InitialFlags;
- PVOID NewBuffer;
- PUCHAR Next;
- UCHAR Op;
- DWARF_LEB128 Operand;
- ULONG OperationAdvance;
- DWARF_SLEB128 SignedOperand;
- DWARF_LEB128 Size;
- PUCHAR Start;
- DWARF_LINE_STATE State;
- INT Status;
- //
- // Read and and potentially print out the header.
- //
- memset(&Header, 0, sizeof(DWARF_LINE_TABLE_HEADER));
- Start = *Table;
- Status = DwarfpReadLineNumberHeader(Table, End, &Header);
- if (Status != 0) {
- goto ProcessLineTableEnd;
- }
- assert(Header.IncludeDirectoryCount >= 1);
- Header.IncludeDirectories[0] = CompileDirectory;
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("Line Table at offset %x\n"
- " UnitLength %I64x %s\n"
- " Version %d\n"
- " Header Length 0x%I64x\n"
- " Minimum Instruction Length %d\n"
- " Default Is Statement: %d\n"
- " Line Base: %d\n"
- " Line Range: %d\n"
- " Opcode Base: %d\n\n"
- " Opcodes:\n",
- (PVOID)Start - Context->Sections.Lines.Data,
- Header.UnitLength,
- Header.Is64Bit ? "64-bit" : "32-bit",
- Header.Version,
- Header.HeaderLength,
- Header.MinimumInstructionLength,
- Header.DefaultIsStatement,
- Header.LineBase,
- Header.LineRange,
- Header.OpcodeBase);
- for (Index = 1; Index < Header.OpcodeBase; Index += 1) {
- DWARF_PRINT(" Opcode %d: %d arguments.\n",
- Index,
- Header.StandardOpcodeLengths[Index]);
- }
- DWARF_PRINT("\n Directory Table:\n");
- for (Index = 0; Index < Header.IncludeDirectoryCount; Index += 1) {
- DWARF_PRINT(" %d: %s\n", Index, Header.IncludeDirectories[Index]);
- }
- DWARF_PRINT("\n File Table\n Index: Directory Time Size Name\n");
- for (Index = 0; Index < Header.FileCount; Index += 1) {
- DWARF_PRINT(" %d: %I64d %I64x %I64d %s\n",
- Index + 1,
- Header.Files[Index].DirectoryIndex,
- Header.Files[Index].ModificationDate,
- Header.Files[Index].FileSize,
- Header.Files[Index].Path);
- }
- DWARF_PRINT("\n Line Statements:\n");
- }
- //
- // Initialize the state machine registers.
- //
- InitialFlags = 0;
- if (Header.DefaultIsStatement != FALSE) {
- InitialFlags |= DWARF_LINE_IS_STATEMENT;
- }
- memset(&State, 0, sizeof(DWARF_LINE_STATE));
- State.Registers.File = 1;
- State.Registers.Line = 1;
- State.Registers.Flags = InitialFlags;
- assert(Header.MaximumOperationsPerInstruction != 0);
- //
- // Loop decoding the line program.
- //
- *Table = Header.ProgramStart;
- while (*Table < Header.End) {
- Op = DwarfpRead1(Table);
- //
- // Most opcodes are special opcodes. Each special opcode does the same
- // thing, they only differ in how far they advance the address/opindex
- // and line. How far they advance depends on values in the header that
- // are tuned per architecture, and the formulas below which come out of
- // the DWARF4 specification.
- //
- if (Op >= Header.OpcodeBase) {
- Op -= Header.OpcodeBase;
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT(" Special op %d ", Op);
- }
- OperationAdvance = Op / Header.LineRange;
- State.Registers.Address +=
- Header.MinimumInstructionLength *
- ((State.Registers.OpIndex + OperationAdvance) /
- Header.MaximumOperationsPerInstruction);
- State.Registers.OpIndex =
- (State.Registers.OpIndex + OperationAdvance) %
- Header.MaximumOperationsPerInstruction;
- State.Registers.Line += Header.LineBase + (Op % Header.LineRange);
- Status = DwarfpEmitLine(Context, &Header, &State);
- if (Status != 0) {
- goto ProcessLineTableEnd;
- }
- State.Registers.Flags &= ~(DWARF_LINE_BASIC_BLOCK |
- DWARF_LINE_PROLOGUE_END |
- DWARF_LINE_EPILOGUE_BEGIN);
- //
- // If the first byte is zero, this is an extended opcode.
- //
- } else if (Op == 0) {
- Size = DwarfpReadLeb128(Table);
- Next = *Table + Size;
- Op = DwarfpRead1(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- if (Op <= DwarfLneSetDiscriminator) {
- DWARF_PRINT(" Extended: %s ",
- DwarfLineExtendedOpNames[Op - 1]);
- } else if (Op >= DwarfLneLowUser) {
- DWARF_PRINT(" Extended: User%d ", Op);
- } else {
- DWARF_PRINT(" Standard: Unknown%d ", Op);
- }
- }
- switch (Op) {
- //
- // Emit one more row using the current registers, set the end
- // sequence boolean in the registers. Then reset the state machine
- // and move to the next sequence.
- //
- case DwarfLneEndSequence:
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT(" End Sequence\n ");
- }
- State.Registers.Flags |= DWARF_LINE_END_SEQUENCE;
- Status = DwarfpEmitLine(Context, &Header, &State);
- if (Status != 0) {
- goto ProcessLineTableEnd;
- }
- memset(&State, 0, sizeof(DWARF_LINE_STATE));
- State.Registers.File = 1;
- State.Registers.Line = 1;
- State.Registers.Flags = InitialFlags;
- break;
- //
- // Set the address to a relocatable target-address-sized address.
- //
- case DwarfLneSetAddress:
- if (AddressSize == 8) {
- State.Registers.Address = DwarfpRead8(Table);
- } else {
- assert(AddressSize == 4);
- State.Registers.Address = DwarfpRead4(Table);
- }
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%I64x ", State.Registers.Address);
- }
- break;
- //
- // Create a new file in the array.
- //
- case DwarfLneDefineFile:
- AllocationSize = (Header.FileCount + 1) *
- sizeof(DWARF_LINE_FILE);
- NewBuffer = realloc(Header.Files, AllocationSize);
- if (NewBuffer == NULL) {
- Status = ENOMEM;
- goto ProcessLineTableEnd;
- }
- Header.Files = NewBuffer;
- File = &(Header.Files[Header.FileCount]);
- File->Path = (PSTR)*Table;
- *Table += strlen(File->Path) + 1;
- File->DirectoryIndex = DwarfpReadLeb128(Table);
- File->ModificationDate = DwarfpReadLeb128(Table);
- File->FileSize = DwarfpReadLeb128(Table);
- File->FileSymbol = NULL;
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%d: %I64d %I64d %I64d %s ",
- Header.FileCount,
- File->DirectoryIndex,
- File->ModificationDate,
- File->FileSize,
- File->Path);
- }
- Header.FileCount += 1;
- break;
- case DwarfLneSetDiscriminator:
- State.Registers.Discriminator = DwarfpReadLeb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%u ", State.Registers.Discriminator);
- }
- break;
- default:
- DWARF_ERROR("DWARF: Unknown extended op %d\n", Op);
- *Table = Next;
- break;
- }
- //
- // The known instructions should have fully used up the
- // instructions, and unknown ones should simply be set to jump
- // over.
- //
- assert(*Table == Next);
- //
- // If it's less than the special opcode base, then it's a standard
- // opcode.
- //
- } else {
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- if (Op <= DwarfLnsSetIsa) {
- DWARF_PRINT(" Standard: %s ",
- DwarfLineStandardOpNames[Op - 1]);
- } else {
- DWARF_PRINT(" Standard: Unknown%d ", Op);
- }
- }
- switch (Op) {
- //
- // Append a new row to the matrix using the current values of the
- // registers. Then reset the booleans.
- //
- case DwarfLnsCopy:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- Status = DwarfpEmitLine(Context, &Header, &State);
- if (Status != 0) {
- goto ProcessLineTableEnd;
- }
- State.Registers.Discriminator = 0;
- State.Registers.Flags &= ~(DWARF_LINE_BASIC_BLOCK |
- DWARF_LINE_PROLOGUE_END |
- DWARF_LINE_EPILOGUE_BEGIN);
- break;
- //
- // Get an single LEB128 operand, and advance the PC and op-index
- // (but not the line) the way the special opcodes do.
- //
- case DwarfLnsAdvancePc:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- Operand = DwarfpReadLeb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%I64u ", Operand);
- }
- State.Registers.Address +=
- Header.MinimumInstructionLength *
- ((State.Registers.OpIndex + Operand) /
- Header.MaximumOperationsPerInstruction);
- State.Registers.OpIndex =
- (State.Registers.OpIndex + Operand) %
- Header.MaximumOperationsPerInstruction;
- break;
- //
- // Simply add the operand to the line.
- //
- case DwarfLnsAdvanceLine:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- SignedOperand = DwarfpReadSleb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%I64d ", SignedOperand);
- }
- State.Registers.Line += SignedOperand;
- break;
- //
- // Set a new file.
- //
- case DwarfLnsSetFile:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- State.Registers.File = DwarfpReadLeb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%u ", State.Registers.File);
- }
- break;
- //
- // Set a new column.
- //
- case DwarfLnsSetColumn:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- State.Registers.Column = DwarfpReadLeb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%u ", State.Registers.Column);
- }
- break;
- //
- // Toggle the is statement flag.
- //
- case DwarfLnsNegateStatement:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- State.Registers.Flags ^= DWARF_LINE_IS_STATEMENT;
- break;
- //
- // Set the basic block flag.
- //
- case DwarfLnsSetBasicBlock:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- State.Registers.Flags |= DWARF_LINE_BASIC_BLOCK;
- break;
- //
- // Advance the address and op-index by the increments corresponding
- // to special register 255 (but don't touch the line number). This
- // allows a slightly more efficient "fast-forward" of the PC.
- //
- case DwarfLnsConstAddPc:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- OperationAdvance = (255 - Header.OpcodeBase) / Header.LineRange;
- State.Registers.Address +=
- Header.MinimumInstructionLength *
- ((State.Registers.OpIndex + OperationAdvance) /
- Header.MaximumOperationsPerInstruction);
- State.Registers.OpIndex =
- (State.Registers.OpIndex + OperationAdvance) %
- Header.MaximumOperationsPerInstruction;
- break;
- //
- // Advance the PC by a fixed size operand and clear op-index. This
- // is supported for simpler assemblers that cannot emit special
- // opcodes.
- //
- case DwarfLnsFixedAdvancePc:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- Operand = DwarfpRead2(Table);
- State.Registers.Address += Operand;
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%u ", (USHORT)Operand);
- }
- State.Registers.OpIndex = 0;
- break;
- //
- // Set the prologue end flag.
- //
- case DwarfLnsSetPrologueEnd:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- State.Registers.Flags |= DWARF_LINE_PROLOGUE_END;
- break;
- //
- // Set the epilogue begin flag.
- //
- case DwarfLnsSetEpilogueBegin:
- assert(Header.StandardOpcodeLengths[Op] == 0);
- State.Registers.Flags |= DWARF_LINE_EPILOGUE_BEGIN;
- break;
- //
- // Set the current instruction set.
- //
- case DwarfLnsSetIsa:
- assert(Header.StandardOpcodeLengths[Op] == 1);
- State.Registers.Isa = DwarfpReadLeb128(Table);
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%u ", State.Registers.Isa);
- }
- break;
- //
- // Advance over the instruction without knowing what it does.
- //
- default:
- Index = Header.StandardOpcodeLengths[Op];
- while (Index != 0) {
- Operand = DwarfpReadLeb128(Table);
- if ((Context->Flags &
- DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("%I64x ", Operand);
- }
- }
- break;
- }
- }
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("\n");
- }
- }
- ProcessLineTableEnd:
- if (Header.IncludeDirectories != NULL) {
- free(Header.IncludeDirectories);
- }
- if (Header.Files != NULL) {
- free(Header.Files);
- }
- return Status;
- }
- INT
- DwarfpEmitLine (
- PDWARF_CONTEXT Context,
- PDWARF_LINE_TABLE_HEADER Header,
- PDWARF_LINE_STATE State
- )
- /*++
- Routine Description:
- This routine emits a line number symbol based on the current DWARF line
- program state.
- Arguments:
- Context - Supplies a pointer to the DWARF context.
- Header - Supplies a pointer to the line table header.
- State - Supplies a pointer to the current line state.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- UINTN DirectoryIndex;
- PSOURCE_FILE_SYMBOL File;
- ULONG FileIndex;
- ULONG Flags;
- PSOURCE_LINE_SYMBOL Line;
- PDWARF_LINE_FILE LineFile;
- PDWARF_LOADING_CONTEXT LoadingContext;
- LoadingContext = Context->LoadingContext;
- assert(LoadingContext->CurrentFile != NULL);
- //
- // First, find the source file symbol, creating it if it does not exist.
- //
- assert(State->Registers.File != 0);
- FileIndex = State->Registers.File - 1;
- if (FileIndex >= Header->FileCount) {
- DWARF_ERROR("DWARF: File index %d bigger than count %d.\n",
- FileIndex,
- Header->FileCount);
- return ERANGE;
- }
- LineFile = &(Header->Files[FileIndex]);
- if (LineFile->FileSymbol != NULL) {
- File = LineFile->FileSymbol;
- } else {
- DirectoryIndex = LineFile->DirectoryIndex;
- if (DirectoryIndex >= Header->IncludeDirectoryCount) {
- DWARF_ERROR("DWARF: Directory index %d bigger than count %d.\n",
- DirectoryIndex,
- Header->IncludeDirectoryCount);
- return ERANGE;
- }
- File = DwarfpFindSource(Context,
- Header->IncludeDirectories[DirectoryIndex],
- LineFile->Path,
- TRUE);
- if (File == NULL) {
- return ENOMEM;
- }
- LineFile->FileSymbol = File;
- }
- if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
- DWARF_PRINT("\n Emit: %s/%s:%d %I64x ",
- File->SourceDirectory,
- File->SourceFile,
- State->Registers.Line,
- State->Registers.Address);
- if (State->Registers.Column != 0) {
- DWARF_PRINT("Column %d ", State->Registers.Column);
- }
- if (State->Registers.OpIndex != 0) {
- DWARF_PRINT("OpIndex %d ", State->Registers.OpIndex);
- }
- if (State->Registers.Discriminator != 0) {
- DWARF_PRINT("Disc %d ", State->Registers.Discriminator);
- }
- if (State->Registers.Isa != 0) {
- DWARF_PRINT("Isa %d ", State->Registers.Isa);
- }
- Flags = State->Registers.Flags;
- if ((Flags & DWARF_LINE_IS_STATEMENT) != 0) {
- DWARF_PRINT("Stmt ");
- }
- if ((Flags & DWARF_LINE_BASIC_BLOCK) != 0) {
- DWARF_PRINT("BasicBlock ");
- }
- if ((Flags & DWARF_LINE_PROLOGUE_END) != 0) {
- DWARF_PRINT("PrologueEnd ");
- }
- if ((Flags & DWARF_LINE_EPILOGUE_BEGIN) != 0) {
- DWARF_PRINT("EpilogueBegin ");
- }
- if ((Flags & DWARF_LINE_END_SEQUENCE) != 0) {
- DWARF_PRINT("End ");
- }
- }
- //
- // Set the end address of the previous line if there is one.
- //
- if (State->PreviousLine != NULL) {
- State->PreviousLine->End = State->Registers.Address;
- }
- //
- // If it's the end sequence, don't create a new line.
- //
- if ((State->Registers.Flags & DWARF_LINE_END_SEQUENCE) != 0) {
- return 0;
- }
- //
- // TODO: Change StartOffset and EndOffset to be absolute always, and
- // remove the owning function from the line symbol.
- //
- Line = malloc(sizeof(SOURCE_LINE_SYMBOL));
- if (Line == NULL) {
- return ENOMEM;
- }
- memset(Line, 0, sizeof(SOURCE_LINE_SYMBOL));
- Line->ParentSource = File;
- Line->LineNumber = State->Registers.Line;
- Line->Start = State->Registers.Address;
- Line->End = Line->Start + 1;
- State->PreviousLine = Line;
- INSERT_BEFORE(&(Line->ListEntry),
- &(LoadingContext->CurrentFile->SourceLinesHead));
- return 0;
- }
- INT
- DwarfpReadLineNumberHeader (
- PUCHAR *Table,
- PUCHAR End,
- PDWARF_LINE_TABLE_HEADER Header
- )
- /*++
- Routine Description:
- This routine reads the DWARF line number program header out of the section.
- Arguments:
- Table - Supplies a pointer that on input contains a pointer to the start of
- the section. On output this pointer will be advanced past the fields
- scanned.
- End - Supplies a pointer to the end of the section.
- Header - Supplies a pointer where the header details will be returned on
- success.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- UINTN Capacity;
- UINTN Count;
- PDWARF_LINE_FILE File;
- PDWARF_LINE_FILE Files;
- UINTN Index;
- PVOID NewBuffer;
- PSTR String;
- DwarfpReadInitialLength(Table, &(Header->Is64Bit), &(Header->UnitLength));
- Header->End = *Table + Header->UnitLength;
- Header->Version = DwarfpRead2(Table);
- Header->HeaderLength = DWARF_READN(Table, Header->Is64Bit);
- Header->ProgramStart = *Table + Header->HeaderLength;
- Header->MinimumInstructionLength = DwarfpRead1(Table);
- Header->MaximumOperationsPerInstruction = 1;
- if (Header->Version >= 4) {
- Header->MaximumOperationsPerInstruction = DwarfpRead1(Table);
- }
- Header->DefaultIsStatement = DwarfpRead1(Table);
- Header->LineBase = DwarfpRead1(Table);
- Header->LineRange = DwarfpRead1(Table);
- Header->OpcodeBase = DwarfpRead1(Table);
- //
- // If too many more standard opcodes are introduced, this structure will
- // need to be adjusted.
- //
- assert(Header->OpcodeBase < sizeof(Header->StandardOpcodeLengths));
- //
- // Opcode zero is ignored since it's the opcode to introduce extended
- // opcodes. Gather the parameter counts for the standard opcodes.
- //
- Header->StandardOpcodeLengths[0] = -1;
- for (Index = 1; Index < Header->OpcodeBase; Index += 1) {
- Header->StandardOpcodeLengths[Index] = DwarfpRead1(Table);
- }
- //
- // Count the include directories, terminated by a null byte. The zeroth
- // entry is always the current compilation unit's compile directory.
- //
- Count = 1;
- String = (PSTR)*Table;
- while (*String != '\0') {
- Count += 1;
- String += strlen(String) + 1;
- }
- Header->IncludeDirectories = malloc((Count + 1) * sizeof(PSTR));
- if (Header->IncludeDirectories == NULL) {
- return ENOMEM;
- }
- memset(Header->IncludeDirectories, 0, (Count + 1) * sizeof(PSTR));
- //
- // Fill in the array of include directories.
- //
- String = (PSTR)*Table;
- Index = 1;
- while (*String != '\0') {
- Header->IncludeDirectories[Index] = String;
- Index += 1;
- String += strlen(String) + 1;
- }
- Header->IncludeDirectoryCount = Index;
- *Table = (PUCHAR)String + 1;
- //
- // Now fill in the array of file entries.
- //
- Capacity = 0;
- Count = 0;
- Files = NULL;
- while (**Table != '\0') {
- //
- // Allocate a new entry if needed.
- //
- if (Capacity <= Count) {
- if (Capacity == 0) {
- Capacity = DWARF_INITIAL_INCLUDE_FILE_CAPACITY;
- } else {
- Capacity *= 2;
- }
- NewBuffer = realloc(Files, Capacity * sizeof(DWARF_LINE_FILE));
- if (NewBuffer == NULL) {
- if (Files != NULL) {
- free(Files);
- }
- return ENOMEM;
- }
- Files = NewBuffer;
- }
- File = &(Files[Count]);
- File->Path = (PSTR)*Table;
- *Table += strlen(File->Path) + 1;
- File->DirectoryIndex = DwarfpReadLeb128(Table);
- File->ModificationDate = DwarfpReadLeb128(Table);
- File->FileSize = DwarfpReadLeb128(Table);
- File->FileSymbol = NULL;
- Count += 1;
- }
- Header->Files = Files;
- Header->FileCount = Count;
- return 0;
- }
|