| ... | ... | @@ -7,8 +7,6 @@ const mem = std.mem; |
| 7 | 7 | const math = std.math; |
| 8 | 8 | const leb = @import("leb128.zig"); |
| 9 | 9 | |
| 10 | | const ArrayList = std.ArrayList; |
| 11 | | |
| 12 | 10 | pub const TAG = @import("dwarf/TAG.zig"); |
| 13 | 11 | pub const AT = @import("dwarf/AT.zig"); |
| 14 | 12 | pub const OP = @import("dwarf/OP.zig"); |
| ... | ... | @@ -157,6 +155,12 @@ const PcRange = struct { |
| 157 | 155 | const Func = struct { |
| 158 | 156 | pc_range: ?PcRange, |
| 159 | 157 | name: ?[]const u8, |
| 158 | |
| 159 | fn deinit(func: *Func, allocator: mem.Allocator) void { |
| 160 | if (func.name) |name| { |
| 161 | allocator.free(name); |
| 162 | } |
| 163 | } |
| 160 | 164 | }; |
| 161 | 165 | |
| 162 | 166 | const CompileUnit = struct { |
| ... | ... | @@ -166,19 +170,30 @@ const CompileUnit = struct { |
| 166 | 170 | pc_range: ?PcRange, |
| 167 | 171 | }; |
| 168 | 172 | |
| 169 | | const AbbrevTable = ArrayList(AbbrevTableEntry); |
| 173 | const AbbrevTable = std.ArrayList(AbbrevTableEntry); |
| 170 | 174 | |
| 171 | 175 | const AbbrevTableHeader = struct { |
| 172 | 176 | // offset from .debug_abbrev |
| 173 | 177 | offset: u64, |
| 174 | 178 | table: AbbrevTable, |
| 179 | |
| 180 | fn deinit(header: *AbbrevTableHeader) void { |
| 181 | for (header.table.items) |*entry| { |
| 182 | entry.deinit(); |
| 183 | } |
| 184 | header.table.deinit(); |
| 185 | } |
| 175 | 186 | }; |
| 176 | 187 | |
| 177 | 188 | const AbbrevTableEntry = struct { |
| 178 | 189 | has_children: bool, |
| 179 | 190 | abbrev_code: u64, |
| 180 | 191 | tag_id: u64, |
| 181 | | attrs: ArrayList(AbbrevAttr), |
| 192 | attrs: std.ArrayList(AbbrevAttr), |
| 193 | |
| 194 | fn deinit(entry: *AbbrevTableEntry) void { |
| 195 | entry.attrs.deinit(); |
| 196 | } |
| 182 | 197 | }; |
| 183 | 198 | |
| 184 | 199 | const AbbrevAttr = struct { |
| ... | ... | @@ -213,15 +228,22 @@ const Constant = struct { |
| 213 | 228 | }; |
| 214 | 229 | |
| 215 | 230 | const Die = struct { |
| 231 | // Arena for Die's Attr's and FormValue's. |
| 232 | arena: std.heap.ArenaAllocator, |
| 216 | 233 | tag_id: u64, |
| 217 | 234 | has_children: bool, |
| 218 | | attrs: ArrayList(Attr), |
| 235 | attrs: std.ArrayListUnmanaged(Attr) = .{}, |
| 219 | 236 | |
| 220 | 237 | const Attr = struct { |
| 221 | 238 | id: u64, |
| 222 | 239 | value: FormValue, |
| 223 | 240 | }; |
| 224 | 241 | |
| 242 | fn deinit(self: *Die, allocator: mem.Allocator) void { |
| 243 | self.arena.deinit(); |
| 244 | self.attrs.deinit(allocator); |
| 245 | } |
| 246 | |
| 225 | 247 | fn getAttr(self: *const Die, id: u64) ?*const FormValue { |
| 226 | 248 | for (self.attrs.items) |*attr| { |
| 227 | 249 | if (attr.id == id) return &attr.value; |
| ... | ... | @@ -292,7 +314,6 @@ const LineNumberProgram = struct { |
| 292 | 314 | default_is_stmt: bool, |
| 293 | 315 | target_address: u64, |
| 294 | 316 | include_dirs: []const []const u8, |
| 295 | | file_entries: *ArrayList(FileEntry), |
| 296 | 317 | |
| 297 | 318 | prev_valid: bool, |
| 298 | 319 | prev_address: u64, |
| ... | ... | @@ -323,7 +344,7 @@ const LineNumberProgram = struct { |
| 323 | 344 | self.prev_end_sequence = undefined; |
| 324 | 345 | } |
| 325 | 346 | |
| 326 | | pub fn init(is_stmt: bool, include_dirs: []const []const u8, file_entries: *ArrayList(FileEntry), target_address: u64) LineNumberProgram { |
| 347 | pub fn init(is_stmt: bool, include_dirs: []const []const u8, target_address: u64) LineNumberProgram { |
| 327 | 348 | return LineNumberProgram{ |
| 328 | 349 | .address = 0, |
| 329 | 350 | .file = 1, |
| ... | ... | @@ -333,7 +354,6 @@ const LineNumberProgram = struct { |
| 333 | 354 | .basic_block = false, |
| 334 | 355 | .end_sequence = false, |
| 335 | 356 | .include_dirs = include_dirs, |
| 336 | | .file_entries = file_entries, |
| 337 | 357 | .default_is_stmt = is_stmt, |
| 338 | 358 | .target_address = target_address, |
| 339 | 359 | .prev_valid = false, |
| ... | ... | @@ -347,24 +367,28 @@ const LineNumberProgram = struct { |
| 347 | 367 | }; |
| 348 | 368 | } |
| 349 | 369 | |
| 350 | | pub fn checkLineMatch(self: *LineNumberProgram) !?debug.LineInfo { |
| 370 | pub fn checkLineMatch( |
| 371 | self: *LineNumberProgram, |
| 372 | allocator: mem.Allocator, |
| 373 | file_entries: []const FileEntry, |
| 374 | ) !?debug.LineInfo { |
| 351 | 375 | if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) { |
| 352 | 376 | const file_entry = if (self.prev_file == 0) { |
| 353 | 377 | return error.MissingDebugInfo; |
| 354 | | } else if (self.prev_file - 1 >= self.file_entries.items.len) { |
| 378 | } else if (self.prev_file - 1 >= file_entries.len) { |
| 355 | 379 | return error.InvalidDebugInfo; |
| 356 | | } else &self.file_entries.items[self.prev_file - 1]; |
| 380 | } else &file_entries[self.prev_file - 1]; |
| 357 | 381 | |
| 358 | 382 | const dir_name = if (file_entry.dir_index >= self.include_dirs.len) { |
| 359 | 383 | return error.InvalidDebugInfo; |
| 360 | 384 | } else self.include_dirs[file_entry.dir_index]; |
| 361 | | const file_name = try fs.path.join(self.file_entries.allocator, &[_][]const u8{ dir_name, file_entry.file_name }); |
| 362 | | errdefer self.file_entries.allocator.free(file_name); |
| 385 | |
| 386 | const file_name = try fs.path.join(allocator, &[_][]const u8{ dir_name, file_entry.file_name }); |
| 387 | |
| 363 | 388 | return debug.LineInfo{ |
| 364 | 389 | .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0, |
| 365 | 390 | .column = self.prev_column, |
| 366 | 391 | .file_name = file_name, |
| 367 | | .allocator = self.file_entries.allocator, |
| 368 | 392 | }; |
| 369 | 393 | } |
| 370 | 394 | |
| ... | ... | @@ -419,8 +443,7 @@ fn parseFormValueBlock(allocator: mem.Allocator, in_stream: anytype, endian: std |
| 419 | 443 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 420 | 444 | } |
| 421 | 445 | |
| 422 | | fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue { |
| 423 | | _ = allocator; |
| 446 | fn parseFormValueConstant(in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue { |
| 424 | 447 | // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here. |
| 425 | 448 | // `nosuspend` should be removed from all the function calls once it is fixed. |
| 426 | 449 | return FormValue{ |
| ... | ... | @@ -447,8 +470,7 @@ fn parseFormValueConstant(allocator: mem.Allocator, in_stream: anytype, signed: |
| 447 | 470 | } |
| 448 | 471 | |
| 449 | 472 | // TODO the nosuspends here are workarounds |
| 450 | | fn parseFormValueRef(allocator: mem.Allocator, in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue { |
| 451 | | _ = allocator; |
| 473 | fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue { |
| 452 | 474 | return FormValue{ |
| 453 | 475 | .Ref = switch (size) { |
| 454 | 476 | 1 => try nosuspend in_stream.readInt(u8, endian), |
| ... | ... | @@ -472,13 +494,13 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en |
| 472 | 494 | const block_len = try nosuspend leb.readULEB128(usize, in_stream); |
| 473 | 495 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 474 | 496 | }, |
| 475 | | FORM.data1 => parseFormValueConstant(allocator, in_stream, false, endian, 1), |
| 476 | | FORM.data2 => parseFormValueConstant(allocator, in_stream, false, endian, 2), |
| 477 | | FORM.data4 => parseFormValueConstant(allocator, in_stream, false, endian, 4), |
| 478 | | FORM.data8 => parseFormValueConstant(allocator, in_stream, false, endian, 8), |
| 497 | FORM.data1 => parseFormValueConstant(in_stream, false, endian, 1), |
| 498 | FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2), |
| 499 | FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4), |
| 500 | FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8), |
| 479 | 501 | FORM.udata, FORM.sdata => { |
| 480 | 502 | const signed = form_id == FORM.sdata; |
| 481 | | return parseFormValueConstant(allocator, in_stream, signed, endian, -1); |
| 503 | return parseFormValueConstant(in_stream, signed, endian, -1); |
| 482 | 504 | }, |
| 483 | 505 | FORM.exprloc => { |
| 484 | 506 | const size = try nosuspend leb.readULEB128(usize, in_stream); |
| ... | ... | @@ -489,11 +511,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en |
| 489 | 511 | FORM.flag_present => FormValue{ .Flag = true }, |
| 490 | 512 | FORM.sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) }, |
| 491 | 513 | |
| 492 | | FORM.ref1 => parseFormValueRef(allocator, in_stream, endian, 1), |
| 493 | | FORM.ref2 => parseFormValueRef(allocator, in_stream, endian, 2), |
| 494 | | FORM.ref4 => parseFormValueRef(allocator, in_stream, endian, 4), |
| 495 | | FORM.ref8 => parseFormValueRef(allocator, in_stream, endian, 8), |
| 496 | | FORM.ref_udata => parseFormValueRef(allocator, in_stream, endian, -1), |
| 514 | FORM.ref1 => parseFormValueRef(in_stream, endian, 1), |
| 515 | FORM.ref2 => parseFormValueRef(in_stream, endian, 2), |
| 516 | FORM.ref4 => parseFormValueRef(in_stream, endian, 4), |
| 517 | FORM.ref8 => parseFormValueRef(in_stream, endian, 8), |
| 518 | FORM.ref_udata => parseFormValueRef(in_stream, endian, -1), |
| 497 | 519 | |
| 498 | 520 | FORM.ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) }, |
| 499 | 521 | FORM.ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) }, |
| ... | ... | @@ -536,12 +558,24 @@ pub const DwarfInfo = struct { |
| 536 | 558 | debug_line_str: ?[]const u8, |
| 537 | 559 | debug_ranges: ?[]const u8, |
| 538 | 560 | // Filled later by the initializer |
| 539 | | abbrev_table_list: ArrayList(AbbrevTableHeader) = undefined, |
| 540 | | compile_unit_list: ArrayList(CompileUnit) = undefined, |
| 541 | | func_list: ArrayList(Func) = undefined, |
| 561 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, |
| 562 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 563 | func_list: std.ArrayListUnmanaged(Func) = .{}, |
| 542 | 564 | |
| 543 | | pub fn allocator(self: DwarfInfo) mem.Allocator { |
| 544 | | return self.abbrev_table_list.allocator; |
| 565 | pub fn deinit(di: *DwarfInfo, allocator: mem.Allocator) void { |
| 566 | for (di.abbrev_table_list.items) |*abbrev| { |
| 567 | abbrev.deinit(); |
| 568 | } |
| 569 | di.abbrev_table_list.deinit(allocator); |
| 570 | for (di.compile_unit_list.items) |*cu| { |
| 571 | cu.die.deinit(allocator); |
| 572 | allocator.destroy(cu.die); |
| 573 | } |
| 574 | di.compile_unit_list.deinit(allocator); |
| 575 | for (di.func_list.items) |*func| { |
| 576 | func.deinit(allocator); |
| 577 | } |
| 578 | di.func_list.deinit(allocator); |
| 545 | 579 | } |
| 546 | 580 | |
| 547 | 581 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { |
| ... | ... | @@ -556,12 +590,16 @@ pub const DwarfInfo = struct { |
| 556 | 590 | return null; |
| 557 | 591 | } |
| 558 | 592 | |
| 559 | | fn scanAllFunctions(di: *DwarfInfo) !void { |
| 593 | fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 560 | 594 | var stream = io.fixedBufferStream(di.debug_info); |
| 561 | 595 | const in = &stream.reader(); |
| 562 | 596 | const seekable = &stream.seekableStream(); |
| 563 | 597 | var this_unit_offset: u64 = 0; |
| 564 | 598 | |
| 599 | var tmp_arena = std.heap.ArenaAllocator.init(allocator); |
| 600 | defer tmp_arena.deinit(); |
| 601 | const arena = tmp_arena.allocator(); |
| 602 | |
| 565 | 603 | while (this_unit_offset < try seekable.getEndPos()) { |
| 566 | 604 | try seekable.seekTo(this_unit_offset); |
| 567 | 605 | |
| ... | ... | @@ -580,26 +618,30 @@ pub const DwarfInfo = struct { |
| 580 | 618 | const unit_type = try in.readInt(u8, di.endian); |
| 581 | 619 | if (unit_type != UT.compile) return error.InvalidDebugInfo; |
| 582 | 620 | address_size = try in.readByte(); |
| 583 | | debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); |
| 621 | debug_abbrev_offset = if (is_64) |
| 622 | try in.readInt(u64, di.endian) |
| 623 | else |
| 624 | try in.readInt(u32, di.endian); |
| 584 | 625 | }, |
| 585 | 626 | else => { |
| 586 | | debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); |
| 627 | debug_abbrev_offset = if (is_64) |
| 628 | try in.readInt(u64, di.endian) |
| 629 | else |
| 630 | try in.readInt(u32, di.endian); |
| 587 | 631 | address_size = try in.readByte(); |
| 588 | 632 | }, |
| 589 | 633 | } |
| 590 | 634 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| 591 | 635 | |
| 592 | 636 | const compile_unit_pos = try seekable.getPos(); |
| 593 | | const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); |
| 637 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 594 | 638 | |
| 595 | 639 | try seekable.seekTo(compile_unit_pos); |
| 596 | 640 | |
| 597 | 641 | const next_unit_pos = this_unit_offset + next_offset; |
| 598 | 642 | |
| 599 | 643 | while ((try seekable.getPos()) < next_unit_pos) { |
| 600 | | const die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse continue; |
| 601 | | defer die_obj.attrs.deinit(); |
| 602 | | |
| 644 | const die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue; |
| 603 | 645 | const after_die_offset = try seekable.getPos(); |
| 604 | 646 | |
| 605 | 647 | switch (die_obj.tag_id) { |
| ... | ... | @@ -607,23 +649,33 @@ pub const DwarfInfo = struct { |
| 607 | 649 | const fn_name = x: { |
| 608 | 650 | var depth: i32 = 3; |
| 609 | 651 | var this_die_obj = die_obj; |
| 610 | | // Prenvent endless loops |
| 652 | // Prevent endless loops |
| 611 | 653 | while (depth > 0) : (depth -= 1) { |
| 612 | 654 | if (this_die_obj.getAttr(AT.name)) |_| { |
| 613 | 655 | const name = try this_die_obj.getAttrString(di, AT.name); |
| 614 | | break :x name; |
| 656 | break :x try allocator.dupe(u8, name); |
| 615 | 657 | } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| { |
| 616 | 658 | // Follow the DIE it points to and repeat |
| 617 | 659 | const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin); |
| 618 | 660 | if (ref_offset > next_offset) return error.InvalidDebugInfo; |
| 619 | 661 | try seekable.seekTo(this_unit_offset + ref_offset); |
| 620 | | this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; |
| 662 | this_die_obj = (try di.parseDie( |
| 663 | arena, |
| 664 | in, |
| 665 | abbrev_table, |
| 666 | is_64, |
| 667 | )) orelse return error.InvalidDebugInfo; |
| 621 | 668 | } else if (this_die_obj.getAttr(AT.specification)) |_| { |
| 622 | 669 | // Follow the DIE it points to and repeat |
| 623 | 670 | const ref_offset = try this_die_obj.getAttrRef(AT.specification); |
| 624 | 671 | if (ref_offset > next_offset) return error.InvalidDebugInfo; |
| 625 | 672 | try seekable.seekTo(this_unit_offset + ref_offset); |
| 626 | | this_die_obj = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; |
| 673 | this_die_obj = (try di.parseDie( |
| 674 | arena, |
| 675 | in, |
| 676 | abbrev_table, |
| 677 | is_64, |
| 678 | )) orelse return error.InvalidDebugInfo; |
| 627 | 679 | } else { |
| 628 | 680 | break :x null; |
| 629 | 681 | } |
| ... | ... | @@ -656,7 +708,7 @@ pub const DwarfInfo = struct { |
| 656 | 708 | } |
| 657 | 709 | }; |
| 658 | 710 | |
| 659 | | try di.func_list.append(Func{ |
| 711 | try di.func_list.append(allocator, Func{ |
| 660 | 712 | .name = fn_name, |
| 661 | 713 | .pc_range = pc_range, |
| 662 | 714 | }); |
| ... | ... | @@ -671,7 +723,7 @@ pub const DwarfInfo = struct { |
| 671 | 723 | } |
| 672 | 724 | } |
| 673 | 725 | |
| 674 | | fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 726 | fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 675 | 727 | var stream = io.fixedBufferStream(di.debug_info); |
| 676 | 728 | const in = &stream.reader(); |
| 677 | 729 | const seekable = &stream.seekableStream(); |
| ... | ... | @@ -695,22 +747,30 @@ pub const DwarfInfo = struct { |
| 695 | 747 | const unit_type = try in.readInt(u8, di.endian); |
| 696 | 748 | if (unit_type != UT.compile) return error.InvalidDebugInfo; |
| 697 | 749 | address_size = try in.readByte(); |
| 698 | | debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); |
| 750 | debug_abbrev_offset = if (is_64) |
| 751 | try in.readInt(u64, di.endian) |
| 752 | else |
| 753 | try in.readInt(u32, di.endian); |
| 699 | 754 | }, |
| 700 | 755 | else => { |
| 701 | | debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); |
| 756 | debug_abbrev_offset = if (is_64) |
| 757 | try in.readInt(u64, di.endian) |
| 758 | else |
| 759 | try in.readInt(u32, di.endian); |
| 702 | 760 | address_size = try in.readByte(); |
| 703 | 761 | }, |
| 704 | 762 | } |
| 705 | 763 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| 706 | 764 | |
| 707 | 765 | const compile_unit_pos = try seekable.getPos(); |
| 708 | | const abbrev_table = try di.getAbbrevTable(debug_abbrev_offset); |
| 766 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 709 | 767 | |
| 710 | 768 | try seekable.seekTo(compile_unit_pos); |
| 711 | 769 | |
| 712 | | const compile_unit_die = try di.allocator().create(Die); |
| 713 | | compile_unit_die.* = (try di.parseDie(in, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; |
| 770 | const compile_unit_die = try allocator.create(Die); |
| 771 | errdefer allocator.destroy(compile_unit_die); |
| 772 | compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse |
| 773 | return error.InvalidDebugInfo; |
| 714 | 774 | |
| 715 | 775 | if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo; |
| 716 | 776 | |
| ... | ... | @@ -738,7 +798,7 @@ pub const DwarfInfo = struct { |
| 738 | 798 | } |
| 739 | 799 | }; |
| 740 | 800 | |
| 741 | | try di.compile_unit_list.append(CompileUnit{ |
| 801 | try di.compile_unit_list.append(allocator, CompileUnit{ |
| 742 | 802 | .version = version, |
| 743 | 803 | .is_64 = is_64, |
| 744 | 804 | .pc_range = pc_range, |
| ... | ... | @@ -797,27 +857,33 @@ pub const DwarfInfo = struct { |
| 797 | 857 | |
| 798 | 858 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 799 | 859 | /// seeks in the stream and parses it. |
| 800 | | fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 860 | fn getAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, abbrev_offset: u64) !*const AbbrevTable { |
| 801 | 861 | for (di.abbrev_table_list.items) |*header| { |
| 802 | 862 | if (header.offset == abbrev_offset) { |
| 803 | 863 | return &header.table; |
| 804 | 864 | } |
| 805 | 865 | } |
| 806 | | try di.abbrev_table_list.append(AbbrevTableHeader{ |
| 866 | try di.abbrev_table_list.append(allocator, AbbrevTableHeader{ |
| 807 | 867 | .offset = abbrev_offset, |
| 808 | | .table = try di.parseAbbrevTable(abbrev_offset), |
| 868 | .table = try di.parseAbbrevTable(allocator, abbrev_offset), |
| 809 | 869 | }); |
| 810 | 870 | return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1].table; |
| 811 | 871 | } |
| 812 | 872 | |
| 813 | | fn parseAbbrevTable(di: *DwarfInfo, offset: u64) !AbbrevTable { |
| 873 | fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable { |
| 814 | 874 | var stream = io.fixedBufferStream(di.debug_abbrev); |
| 815 | 875 | const in = &stream.reader(); |
| 816 | 876 | const seekable = &stream.seekableStream(); |
| 817 | 877 | |
| 818 | 878 | try seekable.seekTo(offset); |
| 819 | | var result = AbbrevTable.init(di.allocator()); |
| 820 | | errdefer result.deinit(); |
| 879 | var result = AbbrevTable.init(allocator); |
| 880 | errdefer { |
| 881 | for (result.items) |*entry| { |
| 882 | entry.attrs.deinit(); |
| 883 | } |
| 884 | result.deinit(); |
| 885 | } |
| 886 | |
| 821 | 887 | while (true) { |
| 822 | 888 | const abbrev_code = try leb.readULEB128(u64, in); |
| 823 | 889 | if (abbrev_code == 0) return result; |
| ... | ... | @@ -825,7 +891,7 @@ pub const DwarfInfo = struct { |
| 825 | 891 | .abbrev_code = abbrev_code, |
| 826 | 892 | .tag_id = try leb.readULEB128(u64, in), |
| 827 | 893 | .has_children = (try in.readByte()) == CHILDREN.yes, |
| 828 | | .attrs = ArrayList(AbbrevAttr).init(di.allocator()), |
| 894 | .attrs = std.ArrayList(AbbrevAttr).init(allocator), |
| 829 | 895 | }); |
| 830 | 896 | const attrs = &result.items[result.items.len - 1].attrs; |
| 831 | 897 | |
| ... | ... | @@ -844,21 +910,34 @@ pub const DwarfInfo = struct { |
| 844 | 910 | } |
| 845 | 911 | } |
| 846 | 912 | |
| 847 | | fn parseDie(di: *DwarfInfo, in_stream: anytype, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { |
| 913 | fn parseDie( |
| 914 | di: *DwarfInfo, |
| 915 | allocator: mem.Allocator, |
| 916 | in_stream: anytype, |
| 917 | abbrev_table: *const AbbrevTable, |
| 918 | is_64: bool, |
| 919 | ) !?Die { |
| 848 | 920 | const abbrev_code = try leb.readULEB128(u64, in_stream); |
| 849 | 921 | if (abbrev_code == 0) return null; |
| 850 | 922 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; |
| 851 | 923 | |
| 852 | 924 | var result = Die{ |
| 925 | // Lives as long as the Die. |
| 926 | .arena = std.heap.ArenaAllocator.init(allocator), |
| 853 | 927 | .tag_id = table_entry.tag_id, |
| 854 | 928 | .has_children = table_entry.has_children, |
| 855 | | .attrs = ArrayList(Die.Attr).init(di.allocator()), |
| 856 | 929 | }; |
| 857 | | try result.attrs.resize(table_entry.attrs.items.len); |
| 930 | try result.attrs.resize(allocator, table_entry.attrs.items.len); |
| 858 | 931 | for (table_entry.attrs.items) |attr, i| { |
| 859 | 932 | result.attrs.items[i] = Die.Attr{ |
| 860 | 933 | .id = attr.attr_id, |
| 861 | | .value = try parseFormValue(di.allocator(), in_stream, attr.form_id, di.endian, is_64), |
| 934 | .value = try parseFormValue( |
| 935 | result.arena.allocator(), |
| 936 | in_stream, |
| 937 | attr.form_id, |
| 938 | di.endian, |
| 939 | is_64, |
| 940 | ), |
| 862 | 941 | }; |
| 863 | 942 | if (attr.form_id == FORM.implicit_const) { |
| 864 | 943 | result.attrs.items[i].value.Const.payload = @bitCast(u64, attr.payload); |
| ... | ... | @@ -867,7 +946,12 @@ pub const DwarfInfo = struct { |
| 867 | 946 | return result; |
| 868 | 947 | } |
| 869 | 948 | |
| 870 | | pub fn getLineNumberInfo(di: *DwarfInfo, compile_unit: CompileUnit, target_address: u64) !debug.LineInfo { |
| 949 | pub fn getLineNumberInfo( |
| 950 | di: *DwarfInfo, |
| 951 | allocator: mem.Allocator, |
| 952 | compile_unit: CompileUnit, |
| 953 | target_address: u64, |
| 954 | ) !debug.LineInfo { |
| 871 | 955 | var stream = io.fixedBufferStream(di.debug_line); |
| 872 | 956 | const in = &stream.reader(); |
| 873 | 957 | const seekable = &stream.seekableStream(); |
| ... | ... | @@ -906,8 +990,8 @@ pub const DwarfInfo = struct { |
| 906 | 990 | |
| 907 | 991 | const opcode_base = try in.readByte(); |
| 908 | 992 | |
| 909 | | const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); |
| 910 | | defer di.allocator().free(standard_opcode_lengths); |
| 993 | const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1); |
| 994 | defer allocator.free(standard_opcode_lengths); |
| 911 | 995 | |
| 912 | 996 | { |
| 913 | 997 | var i: usize = 0; |
| ... | ... | @@ -916,19 +1000,28 @@ pub const DwarfInfo = struct { |
| 916 | 1000 | } |
| 917 | 1001 | } |
| 918 | 1002 | |
| 919 | | var include_directories = ArrayList([]const u8).init(di.allocator()); |
| 1003 | var tmp_arena = std.heap.ArenaAllocator.init(allocator); |
| 1004 | defer tmp_arena.deinit(); |
| 1005 | const arena = tmp_arena.allocator(); |
| 1006 | |
| 1007 | var include_directories = std.ArrayList([]const u8).init(arena); |
| 920 | 1008 | try include_directories.append(compile_unit_cwd); |
| 1009 | |
| 921 | 1010 | while (true) { |
| 922 | | const dir = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize)); |
| 1011 | const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); |
| 923 | 1012 | if (dir.len == 0) break; |
| 924 | 1013 | try include_directories.append(dir); |
| 925 | 1014 | } |
| 926 | 1015 | |
| 927 | | var file_entries = ArrayList(FileEntry).init(di.allocator()); |
| 928 | | var prog = LineNumberProgram.init(default_is_stmt, include_directories.items, &file_entries, target_address); |
| 1016 | var file_entries = std.ArrayList(FileEntry).init(arena); |
| 1017 | var prog = LineNumberProgram.init( |
| 1018 | default_is_stmt, |
| 1019 | include_directories.items, |
| 1020 | target_address, |
| 1021 | ); |
| 929 | 1022 | |
| 930 | 1023 | while (true) { |
| 931 | | const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize)); |
| 1024 | const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); |
| 932 | 1025 | if (file_name.len == 0) break; |
| 933 | 1026 | const dir_index = try leb.readULEB128(usize, in); |
| 934 | 1027 | const mtime = try leb.readULEB128(usize, in); |
| ... | ... | @@ -955,7 +1048,7 @@ pub const DwarfInfo = struct { |
| 955 | 1048 | switch (sub_op) { |
| 956 | 1049 | LNE.end_sequence => { |
| 957 | 1050 | prog.end_sequence = true; |
| 958 | | if (try prog.checkLineMatch()) |info| return info; |
| 1051 | if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info; |
| 959 | 1052 | prog.reset(); |
| 960 | 1053 | }, |
| 961 | 1054 | LNE.set_address => { |
| ... | ... | @@ -963,7 +1056,7 @@ pub const DwarfInfo = struct { |
| 963 | 1056 | prog.address = addr; |
| 964 | 1057 | }, |
| 965 | 1058 | LNE.define_file => { |
| 966 | | const file_name = try in.readUntilDelimiterAlloc(di.allocator(), 0, math.maxInt(usize)); |
| 1059 | const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); |
| 967 | 1060 | const dir_index = try leb.readULEB128(usize, in); |
| 968 | 1061 | const mtime = try leb.readULEB128(usize, in); |
| 969 | 1062 | const len_bytes = try leb.readULEB128(usize, in); |
| ... | ... | @@ -986,12 +1079,12 @@ pub const DwarfInfo = struct { |
| 986 | 1079 | const inc_line = @as(i32, line_base) + @as(i32, adjusted_opcode % line_range); |
| 987 | 1080 | prog.line += inc_line; |
| 988 | 1081 | prog.address += inc_addr; |
| 989 | | if (try prog.checkLineMatch()) |info| return info; |
| 1082 | if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info; |
| 990 | 1083 | prog.basic_block = false; |
| 991 | 1084 | } else { |
| 992 | 1085 | switch (opcode) { |
| 993 | 1086 | LNS.copy => { |
| 994 | | if (try prog.checkLineMatch()) |info| return info; |
| 1087 | if (try prog.checkLineMatch(allocator, file_entries.items)) |info| return info; |
| 995 | 1088 | prog.basic_block = false; |
| 996 | 1089 | }, |
| 997 | 1090 | LNS.advance_pc => { |
| ... | ... | @@ -1068,13 +1161,8 @@ pub const DwarfInfo = struct { |
| 1068 | 1161 | }; |
| 1069 | 1162 | |
| 1070 | 1163 | /// Initialize DWARF info. The caller has the responsibility to initialize most |
| 1071 | | /// the DwarfInfo fields before calling. These fields can be left undefined: |
| 1072 | | /// * abbrev_table_list |
| 1073 | | /// * compile_unit_list |
| 1164 | /// the DwarfInfo fields before calling. |
| 1074 | 1165 | pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 1075 | | di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); |
| 1076 | | di.compile_unit_list = ArrayList(CompileUnit).init(allocator); |
| 1077 | | di.func_list = ArrayList(Func).init(allocator); |
| 1078 | | try di.scanAllFunctions(); |
| 1079 | | try di.scanAllCompileUnits(); |
| 1166 | try di.scanAllFunctions(allocator); |
| 1167 | try di.scanAllCompileUnits(allocator); |
| 1080 | 1168 | } |