| ... | @@ -185,12 +185,17 @@ const ElfStackTrace = struct { | ... | @@ -185,12 +185,17 @@ const ElfStackTrace = struct { |
| 185 | } | 185 | } |
| 186 | }; | 186 | }; |
| 187 | | 187 | |
| | 188 | const PcRange = struct { |
| | 189 | start: u64, |
| | 190 | end: u64, |
| | 191 | }; |
| | 192 | |
| 188 | const CompileUnit = struct { | 193 | const CompileUnit = struct { |
| | 194 | version: u16, |
| 189 | is_64: bool, | 195 | is_64: bool, |
| 190 | die: &Die, | 196 | die: &Die, |
| 191 | pc_start: u64, | | |
| 192 | pc_end: u64, | | |
| 193 | index: usize, | 197 | index: usize, |
| | 198 | pc_range: ?PcRange, |
| 194 | }; | 199 | }; |
| 195 | | 200 | |
| 196 | const AbbrevTable = List(AbbrevTableEntry); | 201 | const AbbrevTable = List(AbbrevTableEntry); |
| ... | @@ -259,7 +264,7 @@ const Die = struct { | ... | @@ -259,7 +264,7 @@ const Die = struct { |
| 259 | } | 264 | } |
| 260 | | 265 | |
| 261 | fn getAttrAddr(self: &const Die, id: u64) -> %u64 { | 266 | fn getAttrAddr(self: &const Die, id: u64) -> %u64 { |
| 262 | const form_value = self.getAttr(id) ?? return error.InvalidDebugInfo; | 267 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 263 | return switch (*form_value) { | 268 | return switch (*form_value) { |
| 264 | FormValue.Address => |value| value, | 269 | FormValue.Address => |value| value, |
| 265 | else => error.InvalidDebugInfo, | 270 | else => error.InvalidDebugInfo, |
| ... | @@ -267,7 +272,7 @@ const Die = struct { | ... | @@ -267,7 +272,7 @@ const Die = struct { |
| 267 | } | 272 | } |
| 268 | | 273 | |
| 269 | fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 { | 274 | fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 { |
| 270 | const form_value = self.getAttr(id) ?? return error.InvalidDebugInfo; | 275 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 271 | return switch (*form_value) { | 276 | return switch (*form_value) { |
| 272 | FormValue.Const => |value| value.asUnsignedLe(), | 277 | FormValue.Const => |value| value.asUnsignedLe(), |
| 273 | else => error.InvalidDebugInfo, | 278 | else => error.InvalidDebugInfo, |
| ... | @@ -275,7 +280,7 @@ const Die = struct { | ... | @@ -275,7 +280,7 @@ const Die = struct { |
| 275 | } | 280 | } |
| 276 | | 281 | |
| 277 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 { | 282 | fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 { |
| 278 | const form_value = self.getAttr(id) ?? return error.InvalidDebugInfo; | 283 | const form_value = self.getAttr(id) ?? return error.MissingDebugInfo; |
| 279 | return switch (*form_value) { | 284 | return switch (*form_value) { |
| 280 | FormValue.String => |value| value, | 285 | FormValue.String => |value| value, |
| 281 | FormValue.StrPtr => |offset| getString(st, offset), | 286 | FormValue.StrPtr => |offset| getString(st, offset), |
| ... | @@ -794,7 +799,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -794,7 +799,7 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 794 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 799 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| 795 | | 800 | |
| 796 | const version = %return st.self_exe_stream.readInt(st.elf.is_big_endian, u16); | 801 | const version = %return st.self_exe_stream.readInt(st.elf.is_big_endian, u16); |
| 797 | if (version != 4) return error.InvalidDebugInfo; | 802 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 798 | | 803 | |
| 799 | const debug_abbrev_offset = if (is_64) { | 804 | const debug_abbrev_offset = if (is_64) { |
| 800 | %return st.self_exe_stream.readInt(st.elf.is_big_endian, u64) | 805 | %return st.self_exe_stream.readInt(st.elf.is_big_endian, u64) |
| ... | @@ -815,22 +820,36 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -815,22 +820,36 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 815 | | 820 | |
| 816 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) | 821 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) |
| 817 | return error.InvalidDebugInfo; | 822 | return error.InvalidDebugInfo; |
| 818 | const low_pc = %return compile_unit_die.getAttrAddr(DW.AT_low_pc); | | |
| 819 | | 823 | |
| 820 | const high_pc_value = compile_unit_die.getAttr(DW.AT_high_pc) ?? return error.MissingDebugInfo; | 824 | const pc_range = { |
| 821 | const pc_end = switch (*high_pc_value) { | 825 | try (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| { |
| 822 | FormValue.Address => |value| value, | 826 | test (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| { |
| 823 | FormValue.Const => |value| { | 827 | const pc_end = switch (*high_pc_value) { |
| 824 | const offset = %return value.asUnsignedLe(); | 828 | FormValue.Address => |value| value, |
| 825 | low_pc + offset | 829 | FormValue.Const => |value| { |
| 826 | }, | 830 | const offset = %return value.asUnsignedLe(); |
| 827 | else => return error.InvalidDebugInfo, | 831 | low_pc + offset |
| | 832 | }, |
| | 833 | else => return error.InvalidDebugInfo, |
| | 834 | }; |
| | 835 | PcRange { |
| | 836 | .start = low_pc, |
| | 837 | .end = pc_end, |
| | 838 | } |
| | 839 | } else { |
| | 840 | null |
| | 841 | } |
| | 842 | } else |err| { |
| | 843 | if (err != error.MissingDebugInfo) |
| | 844 | return err; |
| | 845 | null |
| | 846 | } |
| 828 | }; | 847 | }; |
| 829 | | 848 | |
| 830 | %return st.compile_unit_list.append(CompileUnit { | 849 | %return st.compile_unit_list.append(CompileUnit { |
| | 850 | .version = version, |
| 831 | .is_64 = is_64, | 851 | .is_64 = is_64, |
| 832 | .pc_start = low_pc, | 852 | .pc_range = pc_range, |
| 833 | .pc_end = pc_end, | | |
| 834 | .die = compile_unit_die, | 853 | .die = compile_unit_die, |
| 835 | .index = cu_index, | 854 | .index = cu_index, |
| 836 | }); | 855 | }); |
| ... | @@ -842,8 +861,10 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { | ... | @@ -842,8 +861,10 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 842 | | 861 | |
| 843 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> ?&const CompileUnit { | 862 | fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> ?&const CompileUnit { |
| 844 | for (st.compile_unit_list.toSlice()) |*compile_unit| { | 863 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| 845 | if (target_address >= compile_unit.pc_start and target_address < compile_unit.pc_end) | 864 | test (compile_unit.pc_range) |range| { |
| 846 | return compile_unit; | 865 | if (target_address >= range.start and target_address < range.end) |
| | 866 | return compile_unit; |
| | 867 | } |
| 847 | } | 868 | } |
| 848 | return null; | 869 | return null; |
| 849 | } | 870 | } |