| ... | ... | @@ -717,7 +717,6 @@ pub const DwarfInfo = struct { |
| 717 | 717 | } |
| 718 | 718 | |
| 719 | 719 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { |
| 720 | | // TODO: Can this be binary searched? |
| 721 | 720 | for (di.func_list.items) |*func| { |
| 722 | 721 | if (func.pc_range) |range| { |
| 723 | 722 | if (address >= range.start and address < range.end) { |
| ... | ... | @@ -835,37 +834,56 @@ pub const DwarfInfo = struct { |
| 835 | 834 | break :x null; |
| 836 | 835 | }; |
| 837 | 836 | |
| 838 | | const pc_range = x: { |
| 839 | | if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| { |
| 840 | | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { |
| 841 | | const pc_end = switch (high_pc_value.*) { |
| 842 | | FormValue.Address => |value| value, |
| 843 | | FormValue.Const => |value| b: { |
| 844 | | const offset = try value.asUnsignedLe(); |
| 845 | | break :b (low_pc + offset); |
| 846 | | }, |
| 847 | | else => return badDwarf(), |
| 848 | | }; |
| 849 | | break :x PcRange{ |
| 837 | var found_range = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: { |
| 838 | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { |
| 839 | const pc_end = switch (high_pc_value.*) { |
| 840 | FormValue.Address => |value| value, |
| 841 | FormValue.Const => |value| b: { |
| 842 | const offset = try value.asUnsignedLe(); |
| 843 | break :b (low_pc + offset); |
| 844 | }, |
| 845 | else => return badDwarf(), |
| 846 | }; |
| 847 | |
| 848 | try di.func_list.append(allocator, Func{ |
| 849 | .name = fn_name, |
| 850 | .pc_range = .{ |
| 850 | 851 | .start = low_pc, |
| 851 | 852 | .end = pc_end, |
| 852 | | }; |
| 853 | | } else { |
| 854 | | break :x null; |
| 855 | | } |
| 856 | | } else |err| { |
| 857 | | if (err != error.MissingDebugInfo) return err; |
| 858 | | break :x null; |
| 853 | }, |
| 854 | }); |
| 859 | 855 | } |
| 856 | |
| 857 | break :blk true; |
| 858 | } else |err| blk: { |
| 859 | if (err != error.MissingDebugInfo) return err; |
| 860 | break :blk false; |
| 860 | 861 | }; |
| 861 | 862 | |
| 862 | | // TODO: Debug issue where `puts` in Ubuntu's libc was not found |
| 863 | | //if (fn_name != null and pc_range != null) debug.print("func_list: {s} -> 0x{x}-0x{x}\n", .{fn_name.?, pc_range.?.start, pc_range.?.end}); |
| 863 | if (die_obj.getAttr(AT.ranges)) |ranges_value| blk: { |
| 864 | var iter = DebugRangeIterator.init(ranges_value, di, &compile_unit) catch |err| { |
| 865 | if (err != error.MissingDebugInfo) return err; |
| 866 | break :blk; |
| 867 | }; |
| 868 | |
| 869 | while (try iter.next()) |range| { |
| 870 | found_range = true; |
| 871 | try di.func_list.append(allocator, Func{ |
| 872 | .name = fn_name, |
| 873 | .pc_range = .{ |
| 874 | .start = range.start_addr, |
| 875 | .end = range.end_addr, |
| 876 | }, |
| 877 | }); |
| 878 | } |
| 879 | } |
| 864 | 880 | |
| 865 | | try di.func_list.append(allocator, Func{ |
| 866 | | .name = fn_name, |
| 867 | | .pc_range = pc_range, |
| 868 | | }); |
| 881 | if (!found_range) { |
| 882 | try di.func_list.append(allocator, Func{ |
| 883 | .name = fn_name, |
| 884 | .pc_range = null, |
| 885 | }); |
| 886 | } |
| 869 | 887 | }, |
| 870 | 888 | else => {}, |
| 871 | 889 | } |
| ... | ... | @@ -966,17 +984,18 @@ pub const DwarfInfo = struct { |
| 966 | 984 | } |
| 967 | 985 | } |
| 968 | 986 | |
| 969 | | pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { |
| 970 | | for (di.compile_unit_list.items) |*compile_unit| { |
| 971 | | if (compile_unit.pc_range) |range| { |
| 972 | | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 973 | | } |
| 987 | const DebugRangeIterator = struct { |
| 988 | base_address: u64, |
| 989 | section_type: DwarfSection, |
| 990 | di: *DwarfInfo, |
| 991 | compile_unit: *const CompileUnit, |
| 992 | stream: io.FixedBufferStream([]const u8), |
| 974 | 993 | |
| 975 | | const opt_debug_ranges = if (compile_unit.version >= 5) di.section(.debug_rnglists) else di.section(.debug_ranges); |
| 976 | | const debug_ranges = opt_debug_ranges orelse continue; |
| 994 | pub fn init(ranges_value: *const FormValue, di: *DwarfInfo, compile_unit: *const CompileUnit) !@This() { |
| 995 | const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges; |
| 996 | const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo; |
| 977 | 997 | |
| 978 | | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| 979 | | const ranges_offset = switch (ranges_val.*) { |
| 998 | const ranges_offset = switch (ranges_value.*) { |
| 980 | 999 | .SecOffset => |off| off, |
| 981 | 1000 | .Const => |c| try c.asUnsignedLe(), |
| 982 | 1001 | .RangeListOffset => |idx| off: { |
| ... | ... | @@ -996,8 +1015,7 @@ pub const DwarfInfo = struct { |
| 996 | 1015 | }; |
| 997 | 1016 | |
| 998 | 1017 | var stream = io.fixedBufferStream(debug_ranges); |
| 999 | | const in = &stream.reader(); |
| 1000 | | const seekable = &stream.seekableStream(); |
| 1018 | try stream.seekTo(ranges_offset); |
| 1001 | 1019 | |
| 1002 | 1020 | // All the addresses in the list are relative to the value |
| 1003 | 1021 | // specified by DW_AT.low_pc or to some other value encoded |
| ... | ... | @@ -1008,86 +1026,122 @@ pub const DwarfInfo = struct { |
| 1008 | 1026 | else => return err, |
| 1009 | 1027 | }; |
| 1010 | 1028 | |
| 1011 | | try seekable.seekTo(ranges_offset); |
| 1029 | return .{ |
| 1030 | .base_address = base_address, |
| 1031 | .section_type = section_type, |
| 1032 | .di = di, |
| 1033 | .compile_unit = compile_unit, |
| 1034 | .stream = stream, |
| 1035 | }; |
| 1036 | } |
| 1012 | 1037 | |
| 1013 | | if (compile_unit.version >= 5) { |
| 1014 | | while (true) { |
| 1038 | // Returns the next range in the list, or null if the end was reached. |
| 1039 | pub fn next(self: *@This()) !?struct{ start_addr: u64, end_addr: u64 } { |
| 1040 | const in = self.stream.reader(); |
| 1041 | switch (self.section_type) { |
| 1042 | .debug_rnglists => { |
| 1015 | 1043 | const kind = try in.readByte(); |
| 1016 | 1044 | switch (kind) { |
| 1017 | | RLE.end_of_list => break, |
| 1045 | RLE.end_of_list => return null, |
| 1018 | 1046 | RLE.base_addressx => { |
| 1019 | 1047 | const index = try leb.readULEB128(usize, in); |
| 1020 | | base_address = try di.readDebugAddr(compile_unit.*, index); |
| 1048 | self.base_address = try self.di.readDebugAddr(self.compile_unit.*, index); |
| 1049 | return try self.next(); |
| 1021 | 1050 | }, |
| 1022 | 1051 | RLE.startx_endx => { |
| 1023 | 1052 | const start_index = try leb.readULEB128(usize, in); |
| 1024 | | const start_addr = try di.readDebugAddr(compile_unit.*, start_index); |
| 1053 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); |
| 1025 | 1054 | |
| 1026 | 1055 | const end_index = try leb.readULEB128(usize, in); |
| 1027 | | const end_addr = try di.readDebugAddr(compile_unit.*, end_index); |
| 1056 | const end_addr = try self.di.readDebugAddr(self.compile_unit.*, end_index); |
| 1028 | 1057 | |
| 1029 | | if (target_address >= start_addr and target_address < end_addr) { |
| 1030 | | return compile_unit; |
| 1031 | | } |
| 1058 | return .{ |
| 1059 | .start_addr = start_addr, |
| 1060 | .end_addr = end_addr, |
| 1061 | }; |
| 1032 | 1062 | }, |
| 1033 | 1063 | RLE.startx_length => { |
| 1034 | 1064 | const start_index = try leb.readULEB128(usize, in); |
| 1035 | | const start_addr = try di.readDebugAddr(compile_unit.*, start_index); |
| 1065 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); |
| 1036 | 1066 | |
| 1037 | 1067 | const len = try leb.readULEB128(usize, in); |
| 1038 | 1068 | const end_addr = start_addr + len; |
| 1039 | 1069 | |
| 1040 | | if (target_address >= start_addr and target_address < end_addr) { |
| 1041 | | return compile_unit; |
| 1042 | | } |
| 1070 | return .{ |
| 1071 | .start_addr = start_addr, |
| 1072 | .end_addr = end_addr, |
| 1073 | }; |
| 1043 | 1074 | }, |
| 1044 | 1075 | RLE.offset_pair => { |
| 1045 | 1076 | const start_addr = try leb.readULEB128(usize, in); |
| 1046 | 1077 | const end_addr = try leb.readULEB128(usize, in); |
| 1078 | |
| 1047 | 1079 | // This is the only kind that uses the base address |
| 1048 | | if (target_address >= base_address + start_addr and target_address < base_address + end_addr) { |
| 1049 | | return compile_unit; |
| 1050 | | } |
| 1080 | return .{ |
| 1081 | .start_addr = self.base_address + start_addr, |
| 1082 | .end_addr = self.base_address + end_addr, |
| 1083 | }; |
| 1051 | 1084 | }, |
| 1052 | 1085 | RLE.base_address => { |
| 1053 | | base_address = try in.readInt(usize, di.endian); |
| 1086 | self.base_address = try in.readInt(usize, self.di.endian); |
| 1087 | return try self.next(); |
| 1054 | 1088 | }, |
| 1055 | 1089 | RLE.start_end => { |
| 1056 | | const start_addr = try in.readInt(usize, di.endian); |
| 1057 | | const end_addr = try in.readInt(usize, di.endian); |
| 1058 | | if (target_address >= start_addr and target_address < end_addr) { |
| 1059 | | return compile_unit; |
| 1060 | | } |
| 1090 | const start_addr = try in.readInt(usize, self.di.endian); |
| 1091 | const end_addr = try in.readInt(usize, self.di.endian); |
| 1092 | |
| 1093 | return .{ |
| 1094 | .start_addr = start_addr, |
| 1095 | .end_addr = end_addr, |
| 1096 | }; |
| 1061 | 1097 | }, |
| 1062 | 1098 | RLE.start_length => { |
| 1063 | | const start_addr = try in.readInt(usize, di.endian); |
| 1099 | const start_addr = try in.readInt(usize, self.di.endian); |
| 1064 | 1100 | const len = try leb.readULEB128(usize, in); |
| 1065 | 1101 | const end_addr = start_addr + len; |
| 1066 | | if (target_address >= start_addr and target_address < end_addr) { |
| 1067 | | return compile_unit; |
| 1068 | | } |
| 1102 | |
| 1103 | return .{ |
| 1104 | .start_addr = start_addr, |
| 1105 | .end_addr = end_addr, |
| 1106 | }; |
| 1069 | 1107 | }, |
| 1070 | 1108 | else => return badDwarf(), |
| 1071 | 1109 | } |
| 1072 | | } |
| 1073 | | } else { |
| 1074 | | while (true) { |
| 1075 | | const begin_addr = try in.readInt(usize, di.endian); |
| 1076 | | const end_addr = try in.readInt(usize, di.endian); |
| 1077 | | if (begin_addr == 0 and end_addr == 0) { |
| 1078 | | break; |
| 1079 | | } |
| 1110 | }, |
| 1111 | .debug_ranges => { |
| 1112 | const start_addr = try in.readInt(usize, self.di.endian); |
| 1113 | const end_addr = try in.readInt(usize, self.di.endian); |
| 1114 | if (start_addr == 0 and end_addr == 0) return null; |
| 1115 | |
| 1080 | 1116 | // This entry selects a new value for the base address |
| 1081 | | if (begin_addr == math.maxInt(usize)) { |
| 1082 | | base_address = end_addr; |
| 1083 | | continue; |
| 1084 | | } |
| 1085 | | if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { |
| 1086 | | return compile_unit; |
| 1117 | if (start_addr == math.maxInt(usize)) { |
| 1118 | self.base_address = end_addr; |
| 1119 | return try self.next(); |
| 1087 | 1120 | } |
| 1088 | | } |
| 1121 | |
| 1122 | return .{ |
| 1123 | .start_addr = self.base_address + start_addr, |
| 1124 | .end_addr = self.base_address + end_addr, |
| 1125 | }; |
| 1126 | }, |
| 1127 | else => unreachable, |
| 1089 | 1128 | } |
| 1090 | 1129 | } |
| 1130 | }; |
| 1131 | |
| 1132 | pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { |
| 1133 | for (di.compile_unit_list.items) |*compile_unit| { |
| 1134 | if (compile_unit.pc_range) |range| { |
| 1135 | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 1136 | } |
| 1137 | |
| 1138 | const ranges_value = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| 1139 | var iter = DebugRangeIterator.init(ranges_value, di, compile_unit) catch continue; |
| 1140 | while (try iter.next()) |range| { |
| 1141 | if (target_address >= range.start_addr and target_address < range.end_addr) return compile_unit; |
| 1142 | } |
| 1143 | } |
| 1144 | |
| 1091 | 1145 | return missingDwarf(); |
| 1092 | 1146 | } |
| 1093 | 1147 | |
| ... | ... | @@ -1566,7 +1620,6 @@ pub const DwarfInfo = struct { |
| 1566 | 1620 | } |
| 1567 | 1621 | } |
| 1568 | 1622 | |
| 1569 | | // TODO: Avoiding sorting if has_eh_frame_hdr exists |
| 1570 | 1623 | std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct { |
| 1571 | 1624 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { |
| 1572 | 1625 | _ = ctx; |