| ... | @@ -717,7 +717,6 @@ pub const DwarfInfo = struct { | ... | @@ -717,7 +717,6 @@ pub const DwarfInfo = struct { |
| 717 | } | 717 | } |
| 718 | | 718 | |
| 719 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { | 719 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { |
| 720 | // TODO: Can this be binary searched? | | |
| 721 | for (di.func_list.items) |*func| { | 720 | for (di.func_list.items) |*func| { |
| 722 | if (func.pc_range) |range| { | 721 | if (func.pc_range) |range| { |
| 723 | if (address >= range.start and address < range.end) { | 722 | if (address >= range.start and address < range.end) { |
| ... | @@ -835,37 +834,56 @@ pub const DwarfInfo = struct { | ... | @@ -835,37 +834,56 @@ pub const DwarfInfo = struct { |
| 835 | break :x null; | 834 | break :x null; |
| 836 | }; | 835 | }; |
| 837 | | 836 | |
| 838 | const pc_range = x: { | 837 | var found_range = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: { |
| 839 | if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| { | 838 | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { |
| 840 | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { | 839 | const pc_end = switch (high_pc_value.*) { |
| 841 | const pc_end = switch (high_pc_value.*) { | 840 | FormValue.Address => |value| value, |
| 842 | FormValue.Address => |value| value, | 841 | FormValue.Const => |value| b: { |
| 843 | FormValue.Const => |value| b: { | 842 | const offset = try value.asUnsignedLe(); |
| 844 | const offset = try value.asUnsignedLe(); | 843 | break :b (low_pc + offset); |
| 845 | break :b (low_pc + offset); | 844 | }, |
| 846 | }, | 845 | else => return badDwarf(), |
| 847 | else => return badDwarf(), | 846 | }; |
| 848 | }; | 847 | |
| 849 | break :x PcRange{ | 848 | try di.func_list.append(allocator, Func{ |
| | 849 | .name = fn_name, |
| | 850 | .pc_range = .{ |
| 850 | .start = low_pc, | 851 | .start = low_pc, |
| 851 | .end = pc_end, | 852 | .end = pc_end, |
| 852 | }; | 853 | }, |
| 853 | } else { | 854 | }); |
| 854 | break :x null; | | |
| 855 | } | | |
| 856 | } else |err| { | | |
| 857 | if (err != error.MissingDebugInfo) return err; | | |
| 858 | break :x null; | | |
| 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 (die_obj.getAttr(AT.ranges)) |ranges_value| blk: { |
| 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}); | 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{ | 881 | if (!found_range) { |
| 866 | .name = fn_name, | 882 | try di.func_list.append(allocator, Func{ |
| 867 | .pc_range = pc_range, | 883 | .name = fn_name, |
| 868 | }); | 884 | .pc_range = null, |
| | 885 | }); |
| | 886 | } |
| 869 | }, | 887 | }, |
| 870 | else => {}, | 888 | else => {}, |
| 871 | } | 889 | } |
| ... | @@ -966,17 +984,18 @@ pub const DwarfInfo = struct { | ... | @@ -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 { | 987 | const DebugRangeIterator = struct { |
| 970 | for (di.compile_unit_list.items) |*compile_unit| { | 988 | base_address: u64, |
| 971 | if (compile_unit.pc_range) |range| { | 989 | section_type: DwarfSection, |
| 972 | if (target_address >= range.start and target_address < range.end) return compile_unit; | 990 | di: *DwarfInfo, |
| 973 | } | 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); | 994 | pub fn init(ranges_value: *const FormValue, di: *DwarfInfo, compile_unit: *const CompileUnit) !@This() { |
| 976 | const debug_ranges = opt_debug_ranges orelse continue; | 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; | 998 | const ranges_offset = switch (ranges_value.*) { |
| 979 | const ranges_offset = switch (ranges_val.*) { | | |
| 980 | .SecOffset => |off| off, | 999 | .SecOffset => |off| off, |
| 981 | .Const => |c| try c.asUnsignedLe(), | 1000 | .Const => |c| try c.asUnsignedLe(), |
| 982 | .RangeListOffset => |idx| off: { | 1001 | .RangeListOffset => |idx| off: { |
| ... | @@ -996,8 +1015,7 @@ pub const DwarfInfo = struct { | ... | @@ -996,8 +1015,7 @@ pub const DwarfInfo = struct { |
| 996 | }; | 1015 | }; |
| 997 | | 1016 | |
| 998 | var stream = io.fixedBufferStream(debug_ranges); | 1017 | var stream = io.fixedBufferStream(debug_ranges); |
| 999 | const in = &stream.reader(); | 1018 | try stream.seekTo(ranges_offset); |
| 1000 | const seekable = &stream.seekableStream(); | | |
| 1001 | | 1019 | |
| 1002 | // All the addresses in the list are relative to the value | 1020 | // All the addresses in the list are relative to the value |
| 1003 | // specified by DW_AT.low_pc or to some other value encoded | 1021 | // specified by DW_AT.low_pc or to some other value encoded |
| ... | @@ -1008,86 +1026,122 @@ pub const DwarfInfo = struct { | ... | @@ -1008,86 +1026,122 @@ pub const DwarfInfo = struct { |
| 1008 | else => return err, | 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) { | 1038 | // Returns the next range in the list, or null if the end was reached. |
| 1014 | while (true) { | 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 | const kind = try in.readByte(); | 1043 | const kind = try in.readByte(); |
| 1016 | switch (kind) { | 1044 | switch (kind) { |
| 1017 | RLE.end_of_list => break, | 1045 | RLE.end_of_list => return null, |
| 1018 | RLE.base_addressx => { | 1046 | RLE.base_addressx => { |
| 1019 | const index = try leb.readULEB128(usize, in); | 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 | RLE.startx_endx => { | 1051 | RLE.startx_endx => { |
| 1023 | const start_index = try leb.readULEB128(usize, in); | 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 | const end_index = try leb.readULEB128(usize, in); | 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) { | 1058 | return .{ |
| 1030 | return compile_unit; | 1059 | .start_addr = start_addr, |
| 1031 | } | 1060 | .end_addr = end_addr, |
| | 1061 | }; |
| 1032 | }, | 1062 | }, |
| 1033 | RLE.startx_length => { | 1063 | RLE.startx_length => { |
| 1034 | const start_index = try leb.readULEB128(usize, in); | 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 | const len = try leb.readULEB128(usize, in); | 1067 | const len = try leb.readULEB128(usize, in); |
| 1038 | const end_addr = start_addr + len; | 1068 | const end_addr = start_addr + len; |
| 1039 | | 1069 | |
| 1040 | if (target_address >= start_addr and target_address < end_addr) { | 1070 | return .{ |
| 1041 | return compile_unit; | 1071 | .start_addr = start_addr, |
| 1042 | } | 1072 | .end_addr = end_addr, |
| | 1073 | }; |
| 1043 | }, | 1074 | }, |
| 1044 | RLE.offset_pair => { | 1075 | RLE.offset_pair => { |
| 1045 | const start_addr = try leb.readULEB128(usize, in); | 1076 | const start_addr = try leb.readULEB128(usize, in); |
| 1046 | const end_addr = try leb.readULEB128(usize, in); | 1077 | const end_addr = try leb.readULEB128(usize, in); |
| | 1078 | |
| 1047 | // This is the only kind that uses the base address | 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) { | 1080 | return .{ |
| 1049 | return compile_unit; | 1081 | .start_addr = self.base_address + start_addr, |
| 1050 | } | 1082 | .end_addr = self.base_address + end_addr, |
| | 1083 | }; |
| 1051 | }, | 1084 | }, |
| 1052 | RLE.base_address => { | 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 | RLE.start_end => { | 1089 | RLE.start_end => { |
| 1056 | const start_addr = try in.readInt(usize, di.endian); | 1090 | const start_addr = try in.readInt(usize, self.di.endian); |
| 1057 | const end_addr = try in.readInt(usize, di.endian); | 1091 | const end_addr = try in.readInt(usize, self.di.endian); |
| 1058 | if (target_address >= start_addr and target_address < end_addr) { | 1092 | |
| 1059 | return compile_unit; | 1093 | return .{ |
| 1060 | } | 1094 | .start_addr = start_addr, |
| | 1095 | .end_addr = end_addr, |
| | 1096 | }; |
| 1061 | }, | 1097 | }, |
| 1062 | RLE.start_length => { | 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 | const len = try leb.readULEB128(usize, in); | 1100 | const len = try leb.readULEB128(usize, in); |
| 1065 | const end_addr = start_addr + len; | 1101 | const end_addr = start_addr + len; |
| 1066 | if (target_address >= start_addr and target_address < end_addr) { | 1102 | |
| 1067 | return compile_unit; | 1103 | return .{ |
| 1068 | } | 1104 | .start_addr = start_addr, |
| | 1105 | .end_addr = end_addr, |
| | 1106 | }; |
| 1069 | }, | 1107 | }, |
| 1070 | else => return badDwarf(), | 1108 | else => return badDwarf(), |
| 1071 | } | 1109 | } |
| 1072 | } | 1110 | }, |
| 1073 | } else { | 1111 | .debug_ranges => { |
| 1074 | while (true) { | 1112 | const start_addr = try in.readInt(usize, self.di.endian); |
| 1075 | const begin_addr = try in.readInt(usize, di.endian); | 1113 | const end_addr = try in.readInt(usize, self.di.endian); |
| 1076 | const end_addr = try in.readInt(usize, di.endian); | 1114 | if (start_addr == 0 and end_addr == 0) return null; |
| 1077 | if (begin_addr == 0 and end_addr == 0) { | 1115 | |
| 1078 | break; | | |
| 1079 | } | | |
| 1080 | // This entry selects a new value for the base address | 1116 | // This entry selects a new value for the base address |
| 1081 | if (begin_addr == math.maxInt(usize)) { | 1117 | if (start_addr == math.maxInt(usize)) { |
| 1082 | base_address = end_addr; | 1118 | self.base_address = end_addr; |
| 1083 | continue; | 1119 | return try self.next(); |
| 1084 | } | | |
| 1085 | if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { | | |
| 1086 | return compile_unit; | | |
| 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 | return missingDwarf(); | 1145 | return missingDwarf(); |
| 1092 | } | 1146 | } |
| 1093 | | 1147 | |
| ... | @@ -1566,7 +1620,6 @@ pub const DwarfInfo = struct { | ... | @@ -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 | std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct { | 1623 | std.mem.sort(FrameDescriptionEntry, di.fde_list.items, {}, struct { |
| 1571 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { | 1624 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { |
| 1572 | _ = ctx; | 1625 | _ = ctx; |