| ... | ... | @@ -315,6 +315,21 @@ pub const BinaryAnnotation = union(enum) { |
| 315 | 315 | file_id: ?u32, |
| 316 | 316 | code_offset: u32, |
| 317 | 317 | code_length: ?u32, |
| 318 | |
| 319 | /// Resolves a partial range to a range with a definite length, or returns null if this |
| 320 | /// is not possible. |
| 321 | fn resolve(self: PartialRange, next_code_offset: ?u32) ?Range { |
| 322 | return .{ |
| 323 | .line_offset = self.line_offset, |
| 324 | .file_id = self.file_id, |
| 325 | .code_offset = self.code_offset, |
| 326 | .code_length = b: { |
| 327 | if (self.code_length) |l| break :b l; |
| 328 | const end = next_code_offset orelse return null; |
| 329 | break :b end - self.code_offset; |
| 330 | }, |
| 331 | }; |
| 332 | } |
| 318 | 333 | }; |
| 319 | 334 | |
| 320 | 335 | pub fn init(annotations: Iterator) RangeIterator { |
| ... | ... | @@ -391,6 +406,8 @@ pub const BinaryAnnotation = union(enum) { |
| 391 | 406 | }, |
| 392 | 407 | } |
| 393 | 408 | |
| 409 | // If we have a new code offset, return the previous range if it exists, resolving |
| 410 | // its length if necessary. |
| 394 | 411 | switch (annotation) { |
| 395 | 412 | .change_code_offset, |
| 396 | 413 | .change_code_offset_and_line_offset, |
| ... | ... | @@ -398,38 +415,16 @@ pub const BinaryAnnotation = union(enum) { |
| 398 | 415 | => {}, |
| 399 | 416 | else => continue, |
| 400 | 417 | } |
| 401 | | |
| 402 | | if (self.prev) |*prev| { |
| 403 | | if (prev.code_length == null) { |
| 404 | | prev.code_length = self.curr.code_offset - prev.code_offset; |
| 405 | | } |
| 406 | | } |
| 407 | | |
| 408 | | defer self.prev = .{ |
| 409 | | .code_offset = self.curr.code_offset, |
| 410 | | .code_length = self.curr.code_length, |
| 411 | | .line_offset = self.curr.line_offset, |
| 412 | | .file_id = self.curr.file_id, |
| 413 | | }; |
| 418 | defer self.prev = self.curr; |
| 414 | 419 | const prev = self.prev orelse continue; |
| 415 | | const prev_code_length = prev.code_length orelse continue; |
| 416 | | return .{ |
| 417 | | .code_offset = prev.code_offset, |
| 418 | | .code_length = prev_code_length, |
| 419 | | .line_offset = prev.line_offset, |
| 420 | | .file_id = prev.file_id, |
| 421 | | }; |
| 420 | return prev.resolve(self.curr.code_offset); |
| 422 | 421 | } |
| 423 | 422 | |
| 423 | // If we've processed all the binary operations but still have a previous range leftover |
| 424 | // with a known length, return it. |
| 424 | 425 | const prev = self.prev orelse return null; |
| 425 | 426 | defer self.prev = null; |
| 426 | | const prev_code_length = prev.code_length orelse return null; |
| 427 | | return .{ |
| 428 | | .code_offset = prev.code_offset, |
| 429 | | .code_length = prev_code_length, |
| 430 | | .line_offset = prev.line_offset, |
| 431 | | .file_id = prev.file_id, |
| 432 | | }; |
| 427 | return prev.resolve(null); |
| 433 | 428 | } |
| 434 | 429 | }; |
| 435 | 430 | |
| ... | ... | @@ -452,6 +447,10 @@ pub const BinaryAnnotation = union(enum) { |
| 452 | 447 | try takePackedU32(reader), |
| 453 | 448 | ) orelse return error.ReadFailed; |
| 454 | 449 | switch (op) { |
| 450 | // Microsoft's docs say that invalid is used as padding, though it is left ambiguous |
| 451 | // whether padding is allowed internally or only after all instructions are complete. |
| 452 | // Empircally, the latter appears to be the case, at lest with the output from LLVM that |
| 453 | // I've tested. |
| 455 | 454 | .invalid => return error.EndOfStream, |
| 456 | 455 | .code_offset => return .{ |
| 457 | 456 | .code_offset = try expect(takePackedU32(reader)), |
| ... | ... | @@ -547,13 +546,19 @@ pub const BinaryAnnotation = union(enum) { |
| 547 | 546 | }; |
| 548 | 547 | |
| 549 | 548 | pub fn findInlineeName(self: *const Pdb, inlinee: u32) ?[]const u8 { |
| 549 | // According to LLVM, the high bit *can* be used to indicate that a type index comes from the |
| 550 | // ipi stream in which case that bit needs to be cleared. LLVM doesn't generate data in this |
| 551 | // manner, but we may as well handle it since it just involves a single bitwise and. |
| 552 | // https://llvm.org/docs/PDB/TpiStream.html#type-indices |
| 553 | const type_index = inlinee & 0x7FFFFFFF; |
| 554 | |
| 550 | 555 | var reader: Io.Reader = .fixed(self.ipi orelse return null); |
| 551 | 556 | const header = reader.takeStructPointer(pdb.IpiStreamHeader) catch return null; |
| 552 | | for (header.type_index_begin..header.type_index_end) |type_index| { |
| 557 | for (header.type_index_begin..header.type_index_end) |curr_type_index| { |
| 553 | 558 | const prefix = reader.takeStructPointer(pdb.LfRecordPrefix) catch return null; |
| 554 | 559 | reader.discardAll(prefix.len - @sizeOf(@FieldType(pdb.LfRecordPrefix, "len"))) catch return null; |
| 555 | 560 | |
| 556 | | if (type_index == inlinee) { |
| 561 | if (curr_type_index == type_index) { |
| 557 | 562 | switch (prefix.kind) { |
| 558 | 563 | .func_id => { |
| 559 | 564 | const func: *align(1) pdb.LfFuncId = @ptrCast(prefix); |