dwline.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dwline.c
  5. Abstract:
  6. This module implements support for processing the DWARF 2+ line number
  7. program.
  8. Author:
  9. Evan Green 8-Dec-2015
  10. Environment:
  11. Debug
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/lib/types.h>
  17. #include <minoca/lib/status.h>
  18. #include <minoca/lib/im.h>
  19. #include "dwarfp.h"
  20. #include <assert.h>
  21. #include <errno.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. #define DWARF_LINE_IS_STATEMENT 0x00000001
  29. #define DWARF_LINE_BASIC_BLOCK 0x00000002
  30. #define DWARF_LINE_END_SEQUENCE 0x00000004
  31. #define DWARF_LINE_PROLOGUE_END 0x00000008
  32. #define DWARF_LINE_EPILOGUE_BEGIN 0x00000010
  33. #define DWARF_INITIAL_INCLUDE_FILE_CAPACITY 4
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. /*++
  38. Structure Description:
  39. This structure stores the state of a row in the DWARF line number matrix.
  40. Members:
  41. Address - Stores the current address.
  42. OpIndex - Stores the operation index for Very Long Instruction Word
  43. instructions. For most architectures this is always zero.
  44. File - Stores the file index.
  45. Line - Stores the one-based line number.
  46. Column - Stores the column number.
  47. Flags - Stores the bitfield of flags. See DWARF_LINE_* definitions.
  48. Isa - Stores the instruction set identifier. Zero indicates the
  49. architecturally defined instruction set.
  50. Discriminator - Stores the discriminator for multiple blocks that share the
  51. same file, line, and column. Most of the time this is zero.
  52. --*/
  53. typedef struct _DWARF_LINE {
  54. ULONGLONG Address;
  55. ULONG OpIndex;
  56. ULONG File;
  57. ULONG Line;
  58. ULONG Column;
  59. ULONG Flags;
  60. ULONG Isa;
  61. ULONG Discriminator;
  62. } DWARF_LINE, *PDWARF_LINE;
  63. /*++
  64. Structure Description:
  65. This structure stores the state machine context for a DWARF line number
  66. program.
  67. Members:
  68. Registers - Stores the line registers.
  69. PreviousLine - Stores the previously emitted line number.
  70. --*/
  71. typedef struct _DWARF_LINE_STATE {
  72. DWARF_LINE Registers;
  73. PSOURCE_LINE_SYMBOL PreviousLine;
  74. } DWARF_LINE_STATE, *PDWARF_LINE_STATE;
  75. /*++
  76. Structure Description:
  77. This structure stores the information for a source file in the DWARF line
  78. number program.
  79. Members:
  80. Path - Stores a pointer to a string containing the relative or absolute
  81. path to the file.
  82. DirectoryIndex - Stores the index of the include directory this file lives
  83. in.
  84. ModificationDate - Stores the modification date of the file when it was
  85. read by the compiler.
  86. FileSize - Stores the size of the file when it was read by the compiler.
  87. FileSymbol - Stores a cached pointer to the source file symbol.
  88. --*/
  89. typedef struct _DWARF_LINE_FILE {
  90. PSTR Path;
  91. DWARF_LEB128 DirectoryIndex;
  92. DWARF_LEB128 ModificationDate;
  93. DWARF_LEB128 FileSize;
  94. PSOURCE_FILE_SYMBOL FileSymbol;
  95. } DWARF_LINE_FILE, *PDWARF_LINE_FILE;
  96. /*++
  97. Structure Description:
  98. This structure stores the header of a line table program.
  99. Members:
  100. UnitLength - Stores the size in bytes of the line number information for
  101. this compilation unit, not including this field.
  102. Is64Bit - Stores a boolean indicating whether this table is 64-bit or not.
  103. Version - Stores the table version number.
  104. HeaderLength - Stores the number of bytes following the header length
  105. field to the beginning of the first byte of the line number program
  106. itself. This is 4/8 bytes depending on whether 64-bit mode is in effect.
  107. MinimumInstructionLength - Stores the size in bytes of the smallest target
  108. machine instruction. Line number program opcodes that alter the address
  109. and op-index registers use this and the maximum operations per
  110. instruction member in their calculations.
  111. MaximumOperationsPerInstruction - Stores the maximum number of individual
  112. operations that may be encoded in an instruction. For non-VLIW
  113. architectures, this is 1, and the operation pointer is always the
  114. address register.
  115. DefaultIsStatement - Stores a boolean indicating the initial value of the
  116. is-statement flag.
  117. LineBase - Stores a parameter used in calculating the effects of special
  118. offsets.
  119. LineRange - Stores another parameter used in calculating the effects of
  120. special offsets.
  121. OpcodeBase - Stores the number assigned to the first special opcode (one
  122. higher than the highest standard opcode implemented).
  123. StandardOpcodeLengths - Stores the number of LEB128 operands for each of
  124. the standard opcodes. The first element of the array corresponds to
  125. opcode 1, and the last element corresponds to OpcodeBase - 1.
  126. IncludeDirectories - Stores an array of include paths that the compiler
  127. searched when generating this compilation unit.
  128. IncludeDirectoryCount - Stores the number of elements in the include
  129. directories array, including the space left for the zeroth entry.
  130. Files - Stores an array of include files.
  131. FileCount - Stores the number of elements in the files array.
  132. ProgramStart - Stores a pointer to the start of the line number program.
  133. End - Stores the end of this table.
  134. --*/
  135. typedef struct _DWARF_LINE_TABLE_HEADER {
  136. ULONGLONG UnitLength;
  137. BOOL Is64Bit;
  138. USHORT Version;
  139. ULONGLONG HeaderLength;
  140. UCHAR MinimumInstructionLength;
  141. UCHAR MaximumOperationsPerInstruction;
  142. UCHAR DefaultIsStatement;
  143. CHAR LineBase;
  144. UCHAR LineRange;
  145. UCHAR OpcodeBase;
  146. UCHAR StandardOpcodeLengths[32];
  147. PSTR *IncludeDirectories;
  148. UINTN IncludeDirectoryCount;
  149. PDWARF_LINE_FILE Files;
  150. UINTN FileCount;
  151. PUCHAR ProgramStart;
  152. PUCHAR End;
  153. } DWARF_LINE_TABLE_HEADER, *PDWARF_LINE_TABLE_HEADER;
  154. //
  155. // ----------------------------------------------- Internal Function Prototypes
  156. //
  157. INT
  158. DwarfpProcessLineTable (
  159. PDWARF_CONTEXT Context,
  160. PSTR CompileDirectory,
  161. ULONG AddressSize,
  162. PUCHAR *Table,
  163. PUCHAR End
  164. );
  165. INT
  166. DwarfpEmitLine (
  167. PDWARF_CONTEXT Context,
  168. PDWARF_LINE_TABLE_HEADER Header,
  169. PDWARF_LINE_STATE State
  170. );
  171. INT
  172. DwarfpReadLineNumberHeader (
  173. PUCHAR *Table,
  174. PUCHAR End,
  175. PDWARF_LINE_TABLE_HEADER Header
  176. );
  177. //
  178. // -------------------------------------------------------------------- Globals
  179. //
  180. PSTR DwarfLineStandardOpNames[] = {
  181. "DwarfLnsCopy",
  182. "DwarfLnsAdvancePc",
  183. "DwarfLnsAdvanceLine",
  184. "DwarfLnsSetFile",
  185. "DwarfLnsSetColumn",
  186. "DwarfLnsNegateStatement",
  187. "DwarfLnsSetBasicBlock",
  188. "DwarfLnsConstAddPc",
  189. "DwarfLnsFixedAdvancePc",
  190. "DwarfLnsSetPrologueEnd",
  191. "DwarfLnsSetEpilogueBegin",
  192. "DwarfLnsSetIsa"
  193. };
  194. PSTR DwarfLineExtendedOpNames[] = {
  195. "DwarfLneEndSequence",
  196. "DwarfLneSetAddress",
  197. "DwarfLneDefineFile",
  198. "DwarfLneSetDiscriminator",
  199. };
  200. //
  201. // ------------------------------------------------------------------ Functions
  202. //
  203. INT
  204. DwarfpProcessStatementList (
  205. PDWARF_CONTEXT Context,
  206. PDWARF_DIE Die
  207. )
  208. /*++
  209. Routine Description:
  210. This routine is called on a compile unit DIE to process the line numbers.
  211. Arguments:
  212. Context - Supplies a pointer to the DWARF context.
  213. Die - Supplies a pointer to the compile unit DIE.
  214. Return Value:
  215. 0 on success.
  216. Returns an error number on failure.
  217. --*/
  218. {
  219. PSTR CompileDirectory;
  220. PUCHAR End;
  221. PDWARF_LOADING_CONTEXT LoadingContext;
  222. ULONGLONG Offset;
  223. PDWARF_ATTRIBUTE_VALUE OffsetAttribute;
  224. INT Status;
  225. PUCHAR Table;
  226. PDWARF_COMPILATION_UNIT Unit;
  227. assert(Die->Tag == DwarfTagCompileUnit);
  228. LoadingContext = Context->LoadingContext;
  229. Unit = LoadingContext->CurrentUnit;
  230. CompileDirectory = DwarfpGetStringAttribute(Die, DwarfAtCompDir);
  231. OffsetAttribute = DwarfpGetAttribute(Die, DwarfAtStatementList);
  232. if (OffsetAttribute == NULL) {
  233. return 0;
  234. }
  235. if (!DWARF_SECTION_OFFSET_FORM(OffsetAttribute->Form, Unit)) {
  236. return 0;
  237. }
  238. Offset = OffsetAttribute->Value.Offset;
  239. Table = Context->Sections.Lines.Data;
  240. End = Table + Context->Sections.Lines.Size;
  241. if ((Table == NULL) || (Table == End) || (Table + Offset >= End)) {
  242. DWARF_ERROR("DWARF: Missing line number information.\n");
  243. return 0;
  244. }
  245. Table += Offset;
  246. Status = DwarfpProcessLineTable(Context,
  247. CompileDirectory,
  248. Unit->AddressSize,
  249. &Table,
  250. End);
  251. return Status;
  252. }
  253. //
  254. // --------------------------------------------------------- Internal Functions
  255. //
  256. INT
  257. DwarfpProcessLineTable (
  258. PDWARF_CONTEXT Context,
  259. PSTR CompileDirectory,
  260. ULONG AddressSize,
  261. PUCHAR *Table,
  262. PUCHAR End
  263. )
  264. /*++
  265. Routine Description:
  266. This routine processes a single compilation unit's DWARF line table.
  267. Arguments:
  268. Context - Supplies a pointer to the DWARF context.
  269. CompileDirectory - Supplies a pointer to the compilation unit's directory.
  270. AddressSize - Supplies the size of an address on the target.
  271. Table - Supplies a pointer that on input contains a pointer to the start of
  272. the section. On output this pointer will be advanced past the fields
  273. scanned.
  274. End - Supplies a pointer to the end of the section.
  275. Return Value:
  276. 0 on success.
  277. Returns an error number on failure.
  278. --*/
  279. {
  280. UINTN AllocationSize;
  281. PDWARF_LINE_FILE File;
  282. DWARF_LINE_TABLE_HEADER Header;
  283. UINTN Index;
  284. ULONG InitialFlags;
  285. PVOID NewBuffer;
  286. PUCHAR Next;
  287. UCHAR Op;
  288. DWARF_LEB128 Operand;
  289. ULONG OperationAdvance;
  290. DWARF_SLEB128 SignedOperand;
  291. DWARF_LEB128 Size;
  292. PUCHAR Start;
  293. DWARF_LINE_STATE State;
  294. INT Status;
  295. //
  296. // Read and and potentially print out the header.
  297. //
  298. memset(&Header, 0, sizeof(DWARF_LINE_TABLE_HEADER));
  299. Start = *Table;
  300. Status = DwarfpReadLineNumberHeader(Table, End, &Header);
  301. if (Status != 0) {
  302. goto ProcessLineTableEnd;
  303. }
  304. assert(Header.IncludeDirectoryCount >= 1);
  305. Header.IncludeDirectories[0] = CompileDirectory;
  306. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  307. DWARF_PRINT("Line Table at offset %x\n"
  308. " UnitLength %I64x %s\n"
  309. " Version %d\n"
  310. " Header Length 0x%I64x\n"
  311. " Minimum Instruction Length %d\n"
  312. " Default Is Statement: %d\n"
  313. " Line Base: %d\n"
  314. " Line Range: %d\n"
  315. " Opcode Base: %d\n\n"
  316. " Opcodes:\n",
  317. (PVOID)Start - Context->Sections.Lines.Data,
  318. Header.UnitLength,
  319. Header.Is64Bit ? "64-bit" : "32-bit",
  320. Header.Version,
  321. Header.HeaderLength,
  322. Header.MinimumInstructionLength,
  323. Header.DefaultIsStatement,
  324. Header.LineBase,
  325. Header.LineRange,
  326. Header.OpcodeBase);
  327. for (Index = 1; Index < Header.OpcodeBase; Index += 1) {
  328. DWARF_PRINT(" Opcode %d: %d arguments.\n",
  329. Index,
  330. Header.StandardOpcodeLengths[Index]);
  331. }
  332. DWARF_PRINT("\n Directory Table:\n");
  333. for (Index = 0; Index < Header.IncludeDirectoryCount; Index += 1) {
  334. DWARF_PRINT(" %d: %s\n", Index, Header.IncludeDirectories[Index]);
  335. }
  336. DWARF_PRINT("\n File Table\n Index: Directory Time Size Name\n");
  337. for (Index = 0; Index < Header.FileCount; Index += 1) {
  338. DWARF_PRINT(" %d: %I64d %I64x %I64d %s\n",
  339. Index + 1,
  340. Header.Files[Index].DirectoryIndex,
  341. Header.Files[Index].ModificationDate,
  342. Header.Files[Index].FileSize,
  343. Header.Files[Index].Path);
  344. }
  345. DWARF_PRINT("\n Line Statements:\n");
  346. }
  347. //
  348. // Initialize the state machine registers.
  349. //
  350. InitialFlags = 0;
  351. if (Header.DefaultIsStatement != FALSE) {
  352. InitialFlags |= DWARF_LINE_IS_STATEMENT;
  353. }
  354. memset(&State, 0, sizeof(DWARF_LINE_STATE));
  355. State.Registers.File = 1;
  356. State.Registers.Line = 1;
  357. State.Registers.Flags = InitialFlags;
  358. assert(Header.MaximumOperationsPerInstruction != 0);
  359. //
  360. // Loop decoding the line program.
  361. //
  362. *Table = Header.ProgramStart;
  363. while (*Table < Header.End) {
  364. Op = DwarfpRead1(Table);
  365. //
  366. // Most opcodes are special opcodes. Each special opcode does the same
  367. // thing, they only differ in how far they advance the address/opindex
  368. // and line. How far they advance depends on values in the header that
  369. // are tuned per architecture, and the formulas below which come out of
  370. // the DWARF4 specification.
  371. //
  372. if (Op >= Header.OpcodeBase) {
  373. Op -= Header.OpcodeBase;
  374. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  375. DWARF_PRINT(" Special op %d ", Op);
  376. }
  377. OperationAdvance = Op / Header.LineRange;
  378. State.Registers.Address +=
  379. Header.MinimumInstructionLength *
  380. ((State.Registers.OpIndex + OperationAdvance) /
  381. Header.MaximumOperationsPerInstruction);
  382. State.Registers.OpIndex =
  383. (State.Registers.OpIndex + OperationAdvance) %
  384. Header.MaximumOperationsPerInstruction;
  385. State.Registers.Line += Header.LineBase + (Op % Header.LineRange);
  386. Status = DwarfpEmitLine(Context, &Header, &State);
  387. if (Status != 0) {
  388. goto ProcessLineTableEnd;
  389. }
  390. State.Registers.Flags &= ~(DWARF_LINE_BASIC_BLOCK |
  391. DWARF_LINE_PROLOGUE_END |
  392. DWARF_LINE_EPILOGUE_BEGIN);
  393. //
  394. // If the first byte is zero, this is an extended opcode.
  395. //
  396. } else if (Op == 0) {
  397. Size = DwarfpReadLeb128(Table);
  398. Next = *Table + Size;
  399. Op = DwarfpRead1(Table);
  400. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  401. if (Op <= DwarfLneSetDiscriminator) {
  402. DWARF_PRINT(" Extended: %s ",
  403. DwarfLineExtendedOpNames[Op - 1]);
  404. } else if (Op >= DwarfLneLowUser) {
  405. DWARF_PRINT(" Extended: User%d ", Op);
  406. } else {
  407. DWARF_PRINT(" Standard: Unknown%d ", Op);
  408. }
  409. }
  410. switch (Op) {
  411. //
  412. // Emit one more row using the current registers, set the end
  413. // sequence boolean in the registers. Then reset the state machine
  414. // and move to the next sequence.
  415. //
  416. case DwarfLneEndSequence:
  417. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  418. DWARF_PRINT(" End Sequence\n ");
  419. }
  420. State.Registers.Flags |= DWARF_LINE_END_SEQUENCE;
  421. Status = DwarfpEmitLine(Context, &Header, &State);
  422. if (Status != 0) {
  423. goto ProcessLineTableEnd;
  424. }
  425. memset(&State, 0, sizeof(DWARF_LINE_STATE));
  426. State.Registers.File = 1;
  427. State.Registers.Line = 1;
  428. State.Registers.Flags = InitialFlags;
  429. break;
  430. //
  431. // Set the address to a relocatable target-address-sized address.
  432. //
  433. case DwarfLneSetAddress:
  434. if (AddressSize == 8) {
  435. State.Registers.Address = DwarfpRead8(Table);
  436. } else {
  437. assert(AddressSize == 4);
  438. State.Registers.Address = DwarfpRead4(Table);
  439. }
  440. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  441. DWARF_PRINT("%I64x ", State.Registers.Address);
  442. }
  443. break;
  444. //
  445. // Create a new file in the array.
  446. //
  447. case DwarfLneDefineFile:
  448. AllocationSize = (Header.FileCount + 1) *
  449. sizeof(DWARF_LINE_FILE);
  450. NewBuffer = realloc(Header.Files, AllocationSize);
  451. if (NewBuffer == NULL) {
  452. Status = ENOMEM;
  453. goto ProcessLineTableEnd;
  454. }
  455. Header.Files = NewBuffer;
  456. File = &(Header.Files[Header.FileCount]);
  457. File->Path = (PSTR)*Table;
  458. *Table += strlen(File->Path) + 1;
  459. File->DirectoryIndex = DwarfpReadLeb128(Table);
  460. File->ModificationDate = DwarfpReadLeb128(Table);
  461. File->FileSize = DwarfpReadLeb128(Table);
  462. File->FileSymbol = NULL;
  463. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  464. DWARF_PRINT("%d: %I64d %I64d %I64d %s ",
  465. Header.FileCount,
  466. File->DirectoryIndex,
  467. File->ModificationDate,
  468. File->FileSize,
  469. File->Path);
  470. }
  471. Header.FileCount += 1;
  472. break;
  473. case DwarfLneSetDiscriminator:
  474. State.Registers.Discriminator = DwarfpReadLeb128(Table);
  475. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  476. DWARF_PRINT("%u ", State.Registers.Discriminator);
  477. }
  478. break;
  479. default:
  480. DWARF_ERROR("DWARF: Unknown extended op %d\n", Op);
  481. *Table = Next;
  482. break;
  483. }
  484. //
  485. // The known instructions should have fully used up the
  486. // instructions, and unknown ones should simply be set to jump
  487. // over.
  488. //
  489. assert(*Table == Next);
  490. //
  491. // If it's less than the special opcode base, then it's a standard
  492. // opcode.
  493. //
  494. } else {
  495. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  496. if (Op <= DwarfLnsSetIsa) {
  497. DWARF_PRINT(" Standard: %s ",
  498. DwarfLineStandardOpNames[Op - 1]);
  499. } else {
  500. DWARF_PRINT(" Standard: Unknown%d ", Op);
  501. }
  502. }
  503. switch (Op) {
  504. //
  505. // Append a new row to the matrix using the current values of the
  506. // registers. Then reset the booleans.
  507. //
  508. case DwarfLnsCopy:
  509. assert(Header.StandardOpcodeLengths[Op] == 0);
  510. Status = DwarfpEmitLine(Context, &Header, &State);
  511. if (Status != 0) {
  512. goto ProcessLineTableEnd;
  513. }
  514. State.Registers.Discriminator = 0;
  515. State.Registers.Flags &= ~(DWARF_LINE_BASIC_BLOCK |
  516. DWARF_LINE_PROLOGUE_END |
  517. DWARF_LINE_EPILOGUE_BEGIN);
  518. break;
  519. //
  520. // Get an single LEB128 operand, and advance the PC and op-index
  521. // (but not the line) the way the special opcodes do.
  522. //
  523. case DwarfLnsAdvancePc:
  524. assert(Header.StandardOpcodeLengths[Op] == 1);
  525. Operand = DwarfpReadLeb128(Table);
  526. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  527. DWARF_PRINT("%I64u ", Operand);
  528. }
  529. State.Registers.Address +=
  530. Header.MinimumInstructionLength *
  531. ((State.Registers.OpIndex + Operand) /
  532. Header.MaximumOperationsPerInstruction);
  533. State.Registers.OpIndex =
  534. (State.Registers.OpIndex + Operand) %
  535. Header.MaximumOperationsPerInstruction;
  536. break;
  537. //
  538. // Simply add the operand to the line.
  539. //
  540. case DwarfLnsAdvanceLine:
  541. assert(Header.StandardOpcodeLengths[Op] == 1);
  542. SignedOperand = DwarfpReadSleb128(Table);
  543. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  544. DWARF_PRINT("%I64d ", SignedOperand);
  545. }
  546. State.Registers.Line += SignedOperand;
  547. break;
  548. //
  549. // Set a new file.
  550. //
  551. case DwarfLnsSetFile:
  552. assert(Header.StandardOpcodeLengths[Op] == 1);
  553. State.Registers.File = DwarfpReadLeb128(Table);
  554. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  555. DWARF_PRINT("%u ", State.Registers.File);
  556. }
  557. break;
  558. //
  559. // Set a new column.
  560. //
  561. case DwarfLnsSetColumn:
  562. assert(Header.StandardOpcodeLengths[Op] == 1);
  563. State.Registers.Column = DwarfpReadLeb128(Table);
  564. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  565. DWARF_PRINT("%u ", State.Registers.Column);
  566. }
  567. break;
  568. //
  569. // Toggle the is statement flag.
  570. //
  571. case DwarfLnsNegateStatement:
  572. assert(Header.StandardOpcodeLengths[Op] == 0);
  573. State.Registers.Flags ^= DWARF_LINE_IS_STATEMENT;
  574. break;
  575. //
  576. // Set the basic block flag.
  577. //
  578. case DwarfLnsSetBasicBlock:
  579. assert(Header.StandardOpcodeLengths[Op] == 0);
  580. State.Registers.Flags |= DWARF_LINE_BASIC_BLOCK;
  581. break;
  582. //
  583. // Advance the address and op-index by the increments corresponding
  584. // to special register 255 (but don't touch the line number). This
  585. // allows a slightly more efficient "fast-forward" of the PC.
  586. //
  587. case DwarfLnsConstAddPc:
  588. assert(Header.StandardOpcodeLengths[Op] == 0);
  589. OperationAdvance = (255 - Header.OpcodeBase) / Header.LineRange;
  590. State.Registers.Address +=
  591. Header.MinimumInstructionLength *
  592. ((State.Registers.OpIndex + OperationAdvance) /
  593. Header.MaximumOperationsPerInstruction);
  594. State.Registers.OpIndex =
  595. (State.Registers.OpIndex + OperationAdvance) %
  596. Header.MaximumOperationsPerInstruction;
  597. break;
  598. //
  599. // Advance the PC by a fixed size operand and clear op-index. This
  600. // is supported for simpler assemblers that cannot emit special
  601. // opcodes.
  602. //
  603. case DwarfLnsFixedAdvancePc:
  604. assert(Header.StandardOpcodeLengths[Op] == 1);
  605. Operand = DwarfpRead2(Table);
  606. State.Registers.Address += Operand;
  607. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  608. DWARF_PRINT("%u ", (USHORT)Operand);
  609. }
  610. State.Registers.OpIndex = 0;
  611. break;
  612. //
  613. // Set the prologue end flag.
  614. //
  615. case DwarfLnsSetPrologueEnd:
  616. assert(Header.StandardOpcodeLengths[Op] == 0);
  617. State.Registers.Flags |= DWARF_LINE_PROLOGUE_END;
  618. break;
  619. //
  620. // Set the epilogue begin flag.
  621. //
  622. case DwarfLnsSetEpilogueBegin:
  623. assert(Header.StandardOpcodeLengths[Op] == 0);
  624. State.Registers.Flags |= DWARF_LINE_EPILOGUE_BEGIN;
  625. break;
  626. //
  627. // Set the current instruction set.
  628. //
  629. case DwarfLnsSetIsa:
  630. assert(Header.StandardOpcodeLengths[Op] == 1);
  631. State.Registers.Isa = DwarfpReadLeb128(Table);
  632. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  633. DWARF_PRINT("%u ", State.Registers.Isa);
  634. }
  635. break;
  636. //
  637. // Advance over the instruction without knowing what it does.
  638. //
  639. default:
  640. Index = Header.StandardOpcodeLengths[Op];
  641. while (Index != 0) {
  642. Operand = DwarfpReadLeb128(Table);
  643. if ((Context->Flags &
  644. DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  645. DWARF_PRINT("%I64x ", Operand);
  646. }
  647. }
  648. break;
  649. }
  650. }
  651. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  652. DWARF_PRINT("\n");
  653. }
  654. }
  655. ProcessLineTableEnd:
  656. if (Header.IncludeDirectories != NULL) {
  657. free(Header.IncludeDirectories);
  658. }
  659. if (Header.Files != NULL) {
  660. free(Header.Files);
  661. }
  662. return Status;
  663. }
  664. INT
  665. DwarfpEmitLine (
  666. PDWARF_CONTEXT Context,
  667. PDWARF_LINE_TABLE_HEADER Header,
  668. PDWARF_LINE_STATE State
  669. )
  670. /*++
  671. Routine Description:
  672. This routine emits a line number symbol based on the current DWARF line
  673. program state.
  674. Arguments:
  675. Context - Supplies a pointer to the DWARF context.
  676. Header - Supplies a pointer to the line table header.
  677. State - Supplies a pointer to the current line state.
  678. Return Value:
  679. 0 on success.
  680. Returns an error number on failure.
  681. --*/
  682. {
  683. UINTN DirectoryIndex;
  684. PSOURCE_FILE_SYMBOL File;
  685. ULONG FileIndex;
  686. ULONG Flags;
  687. PSOURCE_LINE_SYMBOL Line;
  688. PDWARF_LINE_FILE LineFile;
  689. PDWARF_LOADING_CONTEXT LoadingContext;
  690. LoadingContext = Context->LoadingContext;
  691. assert(LoadingContext->CurrentFile != NULL);
  692. //
  693. // First, find the source file symbol, creating it if it does not exist.
  694. //
  695. assert(State->Registers.File != 0);
  696. FileIndex = State->Registers.File - 1;
  697. if (FileIndex >= Header->FileCount) {
  698. DWARF_ERROR("DWARF: File index %d bigger than count %d.\n",
  699. FileIndex,
  700. Header->FileCount);
  701. return ERANGE;
  702. }
  703. LineFile = &(Header->Files[FileIndex]);
  704. if (LineFile->FileSymbol != NULL) {
  705. File = LineFile->FileSymbol;
  706. } else {
  707. DirectoryIndex = LineFile->DirectoryIndex;
  708. if (DirectoryIndex >= Header->IncludeDirectoryCount) {
  709. DWARF_ERROR("DWARF: Directory index %d bigger than count %d.\n",
  710. DirectoryIndex,
  711. Header->IncludeDirectoryCount);
  712. return ERANGE;
  713. }
  714. File = DwarfpFindSource(Context,
  715. Header->IncludeDirectories[DirectoryIndex],
  716. LineFile->Path,
  717. TRUE);
  718. if (File == NULL) {
  719. return ENOMEM;
  720. }
  721. LineFile->FileSymbol = File;
  722. }
  723. if ((Context->Flags & DWARF_CONTEXT_DEBUG_LINE_NUMBERS) != 0) {
  724. DWARF_PRINT("\n Emit: %s/%s:%d %I64x ",
  725. File->SourceDirectory,
  726. File->SourceFile,
  727. State->Registers.Line,
  728. State->Registers.Address);
  729. if (State->Registers.Column != 0) {
  730. DWARF_PRINT("Column %d ", State->Registers.Column);
  731. }
  732. if (State->Registers.OpIndex != 0) {
  733. DWARF_PRINT("OpIndex %d ", State->Registers.OpIndex);
  734. }
  735. if (State->Registers.Discriminator != 0) {
  736. DWARF_PRINT("Disc %d ", State->Registers.Discriminator);
  737. }
  738. if (State->Registers.Isa != 0) {
  739. DWARF_PRINT("Isa %d ", State->Registers.Isa);
  740. }
  741. Flags = State->Registers.Flags;
  742. if ((Flags & DWARF_LINE_IS_STATEMENT) != 0) {
  743. DWARF_PRINT("Stmt ");
  744. }
  745. if ((Flags & DWARF_LINE_BASIC_BLOCK) != 0) {
  746. DWARF_PRINT("BasicBlock ");
  747. }
  748. if ((Flags & DWARF_LINE_PROLOGUE_END) != 0) {
  749. DWARF_PRINT("PrologueEnd ");
  750. }
  751. if ((Flags & DWARF_LINE_EPILOGUE_BEGIN) != 0) {
  752. DWARF_PRINT("EpilogueBegin ");
  753. }
  754. if ((Flags & DWARF_LINE_END_SEQUENCE) != 0) {
  755. DWARF_PRINT("End ");
  756. }
  757. }
  758. //
  759. // Set the end address of the previous line if there is one.
  760. //
  761. if (State->PreviousLine != NULL) {
  762. State->PreviousLine->End = State->Registers.Address;
  763. }
  764. //
  765. // If it's the end sequence, don't create a new line.
  766. //
  767. if ((State->Registers.Flags & DWARF_LINE_END_SEQUENCE) != 0) {
  768. return 0;
  769. }
  770. //
  771. // TODO: Change StartOffset and EndOffset to be absolute always, and
  772. // remove the owning function from the line symbol.
  773. //
  774. Line = malloc(sizeof(SOURCE_LINE_SYMBOL));
  775. if (Line == NULL) {
  776. return ENOMEM;
  777. }
  778. memset(Line, 0, sizeof(SOURCE_LINE_SYMBOL));
  779. Line->ParentSource = File;
  780. Line->LineNumber = State->Registers.Line;
  781. Line->Start = State->Registers.Address;
  782. Line->End = Line->Start + 1;
  783. State->PreviousLine = Line;
  784. INSERT_BEFORE(&(Line->ListEntry),
  785. &(LoadingContext->CurrentFile->SourceLinesHead));
  786. return 0;
  787. }
  788. INT
  789. DwarfpReadLineNumberHeader (
  790. PUCHAR *Table,
  791. PUCHAR End,
  792. PDWARF_LINE_TABLE_HEADER Header
  793. )
  794. /*++
  795. Routine Description:
  796. This routine reads the DWARF line number program header out of the section.
  797. Arguments:
  798. Table - Supplies a pointer that on input contains a pointer to the start of
  799. the section. On output this pointer will be advanced past the fields
  800. scanned.
  801. End - Supplies a pointer to the end of the section.
  802. Header - Supplies a pointer where the header details will be returned on
  803. success.
  804. Return Value:
  805. 0 on success.
  806. Returns an error number on failure.
  807. --*/
  808. {
  809. UINTN Capacity;
  810. UINTN Count;
  811. PDWARF_LINE_FILE File;
  812. PDWARF_LINE_FILE Files;
  813. UINTN Index;
  814. PVOID NewBuffer;
  815. PSTR String;
  816. DwarfpReadInitialLength(Table, &(Header->Is64Bit), &(Header->UnitLength));
  817. Header->End = *Table + Header->UnitLength;
  818. Header->Version = DwarfpRead2(Table);
  819. Header->HeaderLength = DWARF_READN(Table, Header->Is64Bit);
  820. Header->ProgramStart = *Table + Header->HeaderLength;
  821. Header->MinimumInstructionLength = DwarfpRead1(Table);
  822. Header->MaximumOperationsPerInstruction = 1;
  823. if (Header->Version >= 4) {
  824. Header->MaximumOperationsPerInstruction = DwarfpRead1(Table);
  825. }
  826. Header->DefaultIsStatement = DwarfpRead1(Table);
  827. Header->LineBase = DwarfpRead1(Table);
  828. Header->LineRange = DwarfpRead1(Table);
  829. Header->OpcodeBase = DwarfpRead1(Table);
  830. //
  831. // If too many more standard opcodes are introduced, this structure will
  832. // need to be adjusted.
  833. //
  834. assert(Header->OpcodeBase < sizeof(Header->StandardOpcodeLengths));
  835. //
  836. // Opcode zero is ignored since it's the opcode to introduce extended
  837. // opcodes. Gather the parameter counts for the standard opcodes.
  838. //
  839. Header->StandardOpcodeLengths[0] = -1;
  840. for (Index = 1; Index < Header->OpcodeBase; Index += 1) {
  841. Header->StandardOpcodeLengths[Index] = DwarfpRead1(Table);
  842. }
  843. //
  844. // Count the include directories, terminated by a null byte. The zeroth
  845. // entry is always the current compilation unit's compile directory.
  846. //
  847. Count = 1;
  848. String = (PSTR)*Table;
  849. while (*String != '\0') {
  850. Count += 1;
  851. String += strlen(String) + 1;
  852. }
  853. Header->IncludeDirectories = malloc((Count + 1) * sizeof(PSTR));
  854. if (Header->IncludeDirectories == NULL) {
  855. return ENOMEM;
  856. }
  857. memset(Header->IncludeDirectories, 0, (Count + 1) * sizeof(PSTR));
  858. //
  859. // Fill in the array of include directories.
  860. //
  861. String = (PSTR)*Table;
  862. Index = 1;
  863. while (*String != '\0') {
  864. Header->IncludeDirectories[Index] = String;
  865. Index += 1;
  866. String += strlen(String) + 1;
  867. }
  868. Header->IncludeDirectoryCount = Index;
  869. *Table = (PUCHAR)String + 1;
  870. //
  871. // Now fill in the array of file entries.
  872. //
  873. Capacity = 0;
  874. Count = 0;
  875. Files = NULL;
  876. while (**Table != '\0') {
  877. //
  878. // Allocate a new entry if needed.
  879. //
  880. if (Capacity <= Count) {
  881. if (Capacity == 0) {
  882. Capacity = DWARF_INITIAL_INCLUDE_FILE_CAPACITY;
  883. } else {
  884. Capacity *= 2;
  885. }
  886. NewBuffer = realloc(Files, Capacity * sizeof(DWARF_LINE_FILE));
  887. if (NewBuffer == NULL) {
  888. if (Files != NULL) {
  889. free(Files);
  890. }
  891. return ENOMEM;
  892. }
  893. Files = NewBuffer;
  894. }
  895. File = &(Files[Count]);
  896. File->Path = (PSTR)*Table;
  897. *Table += strlen(File->Path) + 1;
  898. File->DirectoryIndex = DwarfpReadLeb128(Table);
  899. File->ModificationDate = DwarfpReadLeb128(Table);
  900. File->FileSize = DwarfpReadLeb128(Table);
  901. File->FileSymbol = NULL;
  902. Count += 1;
  903. }
  904. Header->Files = Files;
  905. Header->FileCount = Count;
  906. return 0;
  907. }