| ... | @@ -299,30 +299,7 @@ const Die = struct { | ... | @@ -299,30 +299,7 @@ const Die = struct { |
| 299 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 299 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 300 | return switch (form_value.*) { | 300 | return switch (form_value.*) { |
| 301 | FormValue.Address => |value| value, | 301 | FormValue.Address => |value| value, |
| 302 | FormValue.AddrOffset => |index| { | 302 | FormValue.AddrOffset => |index| di.readDebugAddr(compile_unit, index), |
| 303 | const debug_addr = di.debug_addr orelse return badDwarf(); | | |
| 304 | // addr_base points to the first item after the header, however we | | |
| 305 | // need to read the header to know the size of each item. Empirically, | | |
| 306 | // it may disagree with is_64 on the compile unit. | | |
| 307 | // The header is 8 or 12 bytes depending on is_64. | | |
| 308 | if (compile_unit.addr_base < 8) return badDwarf(); | | |
| 309 | | | |
| 310 | const version = mem.readInt(u16, debug_addr[compile_unit.addr_base - 4 ..][0..2], di.endian); | | |
| 311 | if (version != 5) return badDwarf(); | | |
| 312 | | | |
| 313 | const addr_size = debug_addr[compile_unit.addr_base - 2]; | | |
| 314 | const seg_size = debug_addr[compile_unit.addr_base - 1]; | | |
| 315 | | | |
| 316 | const byte_offset = compile_unit.addr_base + (addr_size + seg_size) * index; | | |
| 317 | if (byte_offset + addr_size > debug_addr.len) return badDwarf(); | | |
| 318 | switch (addr_size) { | | |
| 319 | 1 => return debug_addr[byte_offset], | | |
| 320 | 2 => return mem.readInt(u16, debug_addr[byte_offset..][0..2], di.endian), | | |
| 321 | 4 => return mem.readInt(u32, debug_addr[byte_offset..][0..4], di.endian), | | |
| 322 | 8 => return mem.readInt(u64, debug_addr[byte_offset..][0..8], di.endian), | | |
| 323 | else => return badDwarf(), | | |
| 324 | } | | |
| 325 | }, | | |
| 326 | else => error.InvalidDebugInfo, | 303 | else => error.InvalidDebugInfo, |
| 327 | }; | 304 | }; |
| 328 | } | 305 | } |
| ... | @@ -952,41 +929,119 @@ pub const DwarfInfo = struct { | ... | @@ -952,41 +929,119 @@ pub const DwarfInfo = struct { |
| 952 | if (compile_unit.pc_range) |range| { | 929 | if (compile_unit.pc_range) |range| { |
| 953 | if (target_address >= range.start and target_address < range.end) return compile_unit; | 930 | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 954 | } | 931 | } |
| 955 | if (di.debug_ranges) |debug_ranges| { | | |
| 956 | if (compile_unit.die.getAttrSecOffset(AT.ranges)) |ranges_offset| { | | |
| 957 | var stream = io.fixedBufferStream(debug_ranges); | | |
| 958 | const in = &stream.reader(); | | |
| 959 | const seekable = &stream.seekableStream(); | | |
| 960 | | | |
| 961 | // All the addresses in the list are relative to the value | | |
| 962 | // specified by DW_AT.low_pc or to some other value encoded | | |
| 963 | // in the list itself. | | |
| 964 | // If no starting value is specified use zero. | | |
| 965 | var base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) { | | |
| 966 | error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135 | | |
| 967 | else => return err, | | |
| 968 | }; | | |
| 969 | | 932 | |
| 970 | try seekable.seekTo(ranges_offset); | 933 | const opt_debug_ranges = if (compile_unit.version >= 5) di.debug_rnglists else di.debug_ranges; |
| | 934 | const debug_ranges = opt_debug_ranges orelse continue; |
| | 935 | |
| | 936 | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| | 937 | const ranges_offset = switch (ranges_val.*) { |
| | 938 | .SecOffset => |off| off, |
| | 939 | .RangeListOffset => |idx| off: { |
| | 940 | if (compile_unit.is_64) { |
| | 941 | const offset_loc = @intCast(usize, compile_unit.rnglists_base + 8 * idx); |
| | 942 | if (offset_loc + 8 > debug_ranges.len) return badDwarf(); |
| | 943 | const offset = mem.readInt(u64, debug_ranges[offset_loc..][0..8], di.endian); |
| | 944 | break :off compile_unit.rnglists_base + offset; |
| | 945 | } else { |
| | 946 | const offset_loc = @intCast(usize, compile_unit.rnglists_base + 4 * idx); |
| | 947 | if (offset_loc + 4 > debug_ranges.len) return badDwarf(); |
| | 948 | const offset = mem.readInt(u32, debug_ranges[offset_loc..][0..4], di.endian); |
| | 949 | break :off compile_unit.rnglists_base + offset; |
| | 950 | } |
| | 951 | }, |
| | 952 | else => return badDwarf(), |
| | 953 | }; |
| 971 | | 954 | |
| 972 | while (true) { | 955 | var stream = io.fixedBufferStream(debug_ranges); |
| 973 | const begin_addr = try in.readInt(usize, di.endian); | 956 | const in = &stream.reader(); |
| 974 | const end_addr = try in.readInt(usize, di.endian); | 957 | const seekable = &stream.seekableStream(); |
| 975 | if (begin_addr == 0 and end_addr == 0) { | 958 | |
| 976 | break; | 959 | // All the addresses in the list are relative to the value |
| 977 | } | 960 | // specified by DW_AT.low_pc or to some other value encoded |
| 978 | // This entry selects a new value for the base address | 961 | // in the list itself. |
| 979 | if (begin_addr == math.maxInt(usize)) { | 962 | // If no starting value is specified use zero. |
| 980 | base_address = end_addr; | 963 | var base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) { |
| 981 | continue; | 964 | error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135 |
| 982 | } | 965 | else => return err, |
| 983 | if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { | 966 | }; |
| 984 | return compile_unit; | 967 | |
| 985 | } | 968 | try seekable.seekTo(ranges_offset); |
| | 969 | |
| | 970 | if (compile_unit.version >= 5) { |
| | 971 | while (true) { |
| | 972 | const kind = try in.readByte(); |
| | 973 | switch (kind) { |
| | 974 | RLE.end_of_list => break, |
| | 975 | RLE.base_addressx => { |
| | 976 | const index = try leb.readULEB128(usize, in); |
| | 977 | base_address = try di.readDebugAddr(compile_unit.*, index); |
| | 978 | }, |
| | 979 | RLE.startx_endx => { |
| | 980 | const start_index = try leb.readULEB128(usize, in); |
| | 981 | const start_addr = try di.readDebugAddr(compile_unit.*, start_index); |
| | 982 | |
| | 983 | const end_index = try leb.readULEB128(usize, in); |
| | 984 | const end_addr = try di.readDebugAddr(compile_unit.*, end_index); |
| | 985 | |
| | 986 | if (target_address >= start_addr and target_address < end_addr) { |
| | 987 | return compile_unit; |
| | 988 | } |
| | 989 | }, |
| | 990 | RLE.startx_length => { |
| | 991 | const start_index = try leb.readULEB128(usize, in); |
| | 992 | const start_addr = try di.readDebugAddr(compile_unit.*, start_index); |
| | 993 | |
| | 994 | const len = try leb.readULEB128(usize, in); |
| | 995 | const end_addr = start_addr + len; |
| | 996 | |
| | 997 | if (target_address >= start_addr and target_address < end_addr) { |
| | 998 | return compile_unit; |
| | 999 | } |
| | 1000 | }, |
| | 1001 | RLE.offset_pair => { |
| | 1002 | const start_addr = try leb.readULEB128(usize, in); |
| | 1003 | const end_addr = try leb.readULEB128(usize, in); |
| | 1004 | // This is the only kind that uses the base address |
| | 1005 | if (target_address >= base_address + start_addr and target_address < base_address + end_addr) { |
| | 1006 | return compile_unit; |
| | 1007 | } |
| | 1008 | }, |
| | 1009 | RLE.base_address => { |
| | 1010 | base_address = try in.readInt(usize, di.endian); |
| | 1011 | }, |
| | 1012 | RLE.start_end => { |
| | 1013 | const start_addr = try in.readInt(usize, di.endian); |
| | 1014 | const end_addr = try in.readInt(usize, di.endian); |
| | 1015 | if (target_address >= start_addr and target_address < end_addr) { |
| | 1016 | return compile_unit; |
| | 1017 | } |
| | 1018 | }, |
| | 1019 | RLE.start_length => { |
| | 1020 | const start_addr = try in.readInt(usize, di.endian); |
| | 1021 | const len = try leb.readULEB128(usize, in); |
| | 1022 | const end_addr = start_addr + len; |
| | 1023 | if (target_address >= start_addr and target_address < end_addr) { |
| | 1024 | return compile_unit; |
| | 1025 | } |
| | 1026 | }, |
| | 1027 | else => return badDwarf(), |
| | 1028 | } |
| | 1029 | } |
| | 1030 | } else { |
| | 1031 | while (true) { |
| | 1032 | const begin_addr = try in.readInt(usize, di.endian); |
| | 1033 | const end_addr = try in.readInt(usize, di.endian); |
| | 1034 | if (begin_addr == 0 and end_addr == 0) { |
| | 1035 | break; |
| | 1036 | } |
| | 1037 | // This entry selects a new value for the base address |
| | 1038 | if (begin_addr == math.maxInt(usize)) { |
| | 1039 | base_address = end_addr; |
| | 1040 | continue; |
| | 1041 | } |
| | 1042 | if (target_address >= base_address + begin_addr and target_address < base_address + end_addr) { |
| | 1043 | return compile_unit; |
| 986 | } | 1044 | } |
| 987 | } else |err| { | | |
| 988 | if (err != error.MissingDebugInfo) return err; | | |
| 989 | continue; | | |
| 990 | } | 1045 | } |
| 991 | } | 1046 | } |
| 992 | } | 1047 | } |
| ... | @@ -1366,6 +1421,32 @@ pub const DwarfInfo = struct { | ... | @@ -1366,6 +1421,32 @@ pub const DwarfInfo = struct { |
| 1366 | fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 { | 1421 | fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 { |
| 1367 | return getStringGeneric(di.debug_line_str, offset); | 1422 | return getStringGeneric(di.debug_line_str, offset); |
| 1368 | } | 1423 | } |
| | 1424 | |
| | 1425 | fn readDebugAddr(di: DwarfInfo, compile_unit: CompileUnit, index: u64) !u64 { |
| | 1426 | const debug_addr = di.debug_addr orelse return badDwarf(); |
| | 1427 | |
| | 1428 | // addr_base points to the first item after the header, however we |
| | 1429 | // need to read the header to know the size of each item. Empirically, |
| | 1430 | // it may disagree with is_64 on the compile unit. |
| | 1431 | // The header is 8 or 12 bytes depending on is_64. |
| | 1432 | if (compile_unit.addr_base < 8) return badDwarf(); |
| | 1433 | |
| | 1434 | const version = mem.readInt(u16, debug_addr[compile_unit.addr_base - 4 ..][0..2], di.endian); |
| | 1435 | if (version != 5) return badDwarf(); |
| | 1436 | |
| | 1437 | const addr_size = debug_addr[compile_unit.addr_base - 2]; |
| | 1438 | const seg_size = debug_addr[compile_unit.addr_base - 1]; |
| | 1439 | |
| | 1440 | const byte_offset = @intCast(usize, compile_unit.addr_base + (addr_size + seg_size) * index); |
| | 1441 | if (byte_offset + addr_size > debug_addr.len) return badDwarf(); |
| | 1442 | return switch (addr_size) { |
| | 1443 | 1 => debug_addr[byte_offset], |
| | 1444 | 2 => mem.readInt(u16, debug_addr[byte_offset..][0..2], di.endian), |
| | 1445 | 4 => mem.readInt(u32, debug_addr[byte_offset..][0..4], di.endian), |
| | 1446 | 8 => mem.readInt(u64, debug_addr[byte_offset..][0..8], di.endian), |
| | 1447 | else => badDwarf(), |
| | 1448 | }; |
| | 1449 | } |
| 1369 | }; | 1450 | }; |
| 1370 | | 1451 | |
| 1371 | /// Initialize DWARF info. The caller has the responsibility to initialize most | 1452 | /// Initialize DWARF info. The caller has the responsibility to initialize most |