| ... | @@ -279,10 +279,11 @@ pub const Die = struct { | ... | @@ -279,10 +279,11 @@ pub const Die = struct { |
| 279 | }; | 279 | }; |
| 280 | } | 280 | } |
| 281 | | 281 | |
| 282 | fn getAttrRef(self: *const Die, id: u64) !u64 { | 282 | fn getAttrRef(self: *const Die, id: u64, unit_offset: u64, unit_len: u64) !u64 { |
| 283 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 283 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 284 | return switch (form_value.*) { | 284 | return switch (form_value.*) { |
| 285 | .ref => |value| value, | 285 | .ref => |offset| if (offset < unit_len) unit_offset + offset else bad(), |
| | 286 | .ref_addr => |addr| addr, |
| 286 | else => bad(), | 287 | else => bad(), |
| 287 | }; | 288 | }; |
| 288 | } | 289 | } |
| ... | @@ -428,14 +429,14 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -428,14 +429,14 @@ pub const ExceptionFrameHeader = struct { |
| 428 | }; | 429 | }; |
| 429 | | 430 | |
| 430 | const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); | 431 | const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); |
| 431 | if (!self.isValidPtr(u8, @intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); | 432 | if (fde_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); |
| 432 | if (fde_entry_header.type != .fde) return bad(); | 433 | if (fde_entry_header.type != .fde) return bad(); |
| 433 | | 434 | |
| 434 | // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable | 435 | // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable |
| 435 | const cie_offset = fde_entry_header.type.fde; | 436 | const cie_offset = fde_entry_header.type.fde; |
| 436 | try eh_frame_fbr.seekTo(cie_offset); | 437 | try eh_frame_fbr.seekTo(cie_offset); |
| 437 | const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); | 438 | const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, if (eh_frame_len == null) ma else null, .eh_frame); |
| 438 | if (!self.isValidPtr(u8, @intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); | 439 | if (cie_entry_header.entry_bytes.len > 0 and !self.isValidPtr(u8, @intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), ma, eh_frame_len)) return bad(); |
| 439 | if (cie_entry_header.type != .cie) return bad(); | 440 | if (cie_entry_header.type != .cie) return bad(); |
| 440 | | 441 | |
| 441 | cie.* = try CommonInformationEntry.parse( | 442 | cie.* = try CommonInformationEntry.parse( |
| ... | @@ -942,13 +943,12 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void { | ... | @@ -942,13 +943,12 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void { |
| 942 | defer fbr.pos = after_die_offset; | 943 | defer fbr.pos = after_die_offset; |
| 943 | | 944 | |
| 944 | // Follow the DIE it points to and repeat | 945 | // Follow the DIE it points to and repeat |
| 945 | const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin); | 946 | const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin, this_unit_offset, next_offset); |
| 946 | if (ref_offset > next_offset) return bad(); | 947 | try fbr.seekTo(ref_offset); |
| 947 | try fbr.seekTo(this_unit_offset + ref_offset); | | |
| 948 | this_die_obj = (try parseDie( | 948 | this_die_obj = (try parseDie( |
| 949 | &fbr, | 949 | &fbr, |
| 950 | attrs_bufs[2], | 950 | attrs_bufs[2], |
| 951 | abbrev_table, | 951 | abbrev_table, // wrong abbrev table for different cu |
| 952 | unit_header.format, | 952 | unit_header.format, |
| 953 | )) orelse return bad(); | 953 | )) orelse return bad(); |
| 954 | } else if (this_die_obj.getAttr(AT.specification)) |_| { | 954 | } else if (this_die_obj.getAttr(AT.specification)) |_| { |
| ... | @@ -956,13 +956,12 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void { | ... | @@ -956,13 +956,12 @@ fn scanAllFunctions(di: *Dwarf, allocator: Allocator) ScanError!void { |
| 956 | defer fbr.pos = after_die_offset; | 956 | defer fbr.pos = after_die_offset; |
| 957 | | 957 | |
| 958 | // Follow the DIE it points to and repeat | 958 | // Follow the DIE it points to and repeat |
| 959 | const ref_offset = try this_die_obj.getAttrRef(AT.specification); | 959 | const ref_offset = try this_die_obj.getAttrRef(AT.specification, this_unit_offset, next_offset); |
| 960 | if (ref_offset > next_offset) return bad(); | 960 | try fbr.seekTo(ref_offset); |
| 961 | try fbr.seekTo(this_unit_offset + ref_offset); | | |
| 962 | this_die_obj = (try parseDie( | 961 | this_die_obj = (try parseDie( |
| 963 | &fbr, | 962 | &fbr, |
| 964 | attrs_bufs[2], | 963 | attrs_bufs[2], |
| 965 | abbrev_table, | 964 | abbrev_table, // wrong abbrev table for different cu |
| 966 | unit_header.format, | 965 | unit_header.format, |
| 967 | )) orelse return bad(); | 966 | )) orelse return bad(); |
| 968 | } else { | 967 | } else { |
| ... | @@ -1494,7 +1493,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! | ... | @@ -1494,7 +1493,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! |
| 1494 | } | 1493 | } |
| 1495 | } else { | 1494 | } else { |
| 1496 | const FileEntFmt = struct { | 1495 | const FileEntFmt = struct { |
| 1497 | content_type_code: u8, | 1496 | content_type_code: u16, |
| 1498 | form_code: u16, | 1497 | form_code: u16, |
| 1499 | }; | 1498 | }; |
| 1500 | { | 1499 | { |
| ... | @@ -1539,7 +1538,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! | ... | @@ -1539,7 +1538,7 @@ fn runLineNumberProgram(d: *Dwarf, gpa: Allocator, compile_unit: *CompileUnit) ! |
| 1539 | if (file_name_entry_format_count > file_ent_fmt_buf.len) return bad(); | 1538 | if (file_name_entry_format_count > file_ent_fmt_buf.len) return bad(); |
| 1540 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| { | 1539 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| { |
| 1541 | ent_fmt.* = .{ | 1540 | ent_fmt.* = .{ |
| 1542 | .content_type_code = try fbr.readUleb128(u8), | 1541 | .content_type_code = try fbr.readUleb128(u16), |
| 1543 | .form_code = try fbr.readUleb128(u16), | 1542 | .form_code = try fbr.readUleb128(u16), |
| 1544 | }; | 1543 | }; |
| 1545 | } | 1544 | } |