| ... | @@ -1,12 +1,9 @@ | ... | @@ -1,12 +1,9 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std.zig"); | 2 | const std = @import("std.zig"); |
| 3 | const debug = std.debug; | 3 | const debug = std.debug; |
| 4 | const fs = std.fs; | | |
| 5 | const io = std.io; | | |
| 6 | const mem = std.mem; | 4 | const mem = std.mem; |
| 7 | const math = std.math; | 5 | const math = std.math; |
| 8 | const leb = @import("leb128.zig"); | 6 | const assert = debug.assert; |
| 9 | const assert = std.debug.assert; | | |
| 10 | const native_endian = builtin.cpu.arch.endian(); | 7 | const native_endian = builtin.cpu.arch.endian(); |
| 11 | | 8 | |
| 12 | pub const TAG = @import("dwarf/TAG.zig"); | 9 | pub const TAG = @import("dwarf/TAG.zig"); |
| ... | @@ -167,8 +164,8 @@ const Func = struct { | ... | @@ -167,8 +164,8 @@ const Func = struct { |
| 167 | | 164 | |
| 168 | pub const CompileUnit = struct { | 165 | pub const CompileUnit = struct { |
| 169 | version: u16, | 166 | version: u16, |
| 170 | is_64: bool, | 167 | format: Format, |
| 171 | die: *Die, | 168 | die: Die, |
| 172 | pc_range: ?PcRange, | 169 | pc_range: ?PcRange, |
| 173 | | 170 | |
| 174 | str_offsets_base: usize, | 171 | str_offsets_base: usize, |
| ... | @@ -178,101 +175,88 @@ pub const CompileUnit = struct { | ... | @@ -178,101 +175,88 @@ pub const CompileUnit = struct { |
| 178 | frame_base: ?*const FormValue, | 175 | frame_base: ?*const FormValue, |
| 179 | }; | 176 | }; |
| 180 | | 177 | |
| 181 | const AbbrevTable = std.ArrayList(AbbrevTableEntry); | 178 | const Abbrev = struct { |
| 182 | | 179 | code: u64, |
| 183 | const AbbrevTableHeader = struct { | | |
| 184 | // offset from .debug_abbrev | | |
| 185 | offset: u64, | | |
| 186 | table: AbbrevTable, | | |
| 187 | | | |
| 188 | fn deinit(header: *AbbrevTableHeader) void { | | |
| 189 | for (header.table.items) |*entry| { | | |
| 190 | entry.deinit(); | | |
| 191 | } | | |
| 192 | header.table.deinit(); | | |
| 193 | } | | |
| 194 | }; | | |
| 195 | | | |
| 196 | const AbbrevTableEntry = struct { | | |
| 197 | has_children: bool, | | |
| 198 | abbrev_code: u64, | | |
| 199 | tag_id: u64, | 180 | tag_id: u64, |
| 200 | attrs: std.ArrayList(AbbrevAttr), | 181 | has_children: bool, |
| | 182 | attrs: []Attr, |
| 201 | | 183 | |
| 202 | fn deinit(entry: *AbbrevTableEntry) void { | 184 | fn deinit(abbrev: *Abbrev, allocator: mem.Allocator) void { |
| 203 | entry.attrs.deinit(); | 185 | allocator.free(abbrev.attrs); |
| | 186 | abbrev.* = undefined; |
| 204 | } | 187 | } |
| 205 | }; | | |
| 206 | | 188 | |
| 207 | const AbbrevAttr = struct { | 189 | const Attr = struct { |
| 208 | attr_id: u64, | 190 | id: u64, |
| 209 | form_id: u64, | 191 | form_id: u64, |
| 210 | /// Only valid if form_id is .implicit_const | 192 | /// Only valid if form_id is .implicit_const |
| 211 | payload: i64, | 193 | payload: i64, |
| 212 | }; | 194 | }; |
| 213 | | 195 | |
| 214 | pub const FormValue = union(enum) { | 196 | const Table = struct { |
| 215 | Address: u64, | 197 | // offset from .debug_abbrev |
| 216 | AddrOffset: usize, | 198 | offset: u64, |
| 217 | Block: []u8, | 199 | abbrevs: []Abbrev, |
| 218 | Const: Constant, | 200 | |
| 219 | ExprLoc: []u8, | 201 | fn deinit(table: *Table, allocator: mem.Allocator) void { |
| 220 | Flag: bool, | 202 | for (table.abbrevs) |*abbrev| { |
| 221 | SecOffset: u64, | 203 | abbrev.deinit(allocator); |
| 222 | Ref: u64, | 204 | } |
| 223 | RefAddr: u64, | 205 | allocator.free(table.abbrevs); |
| 224 | String: []const u8, | 206 | table.* = undefined; |
| 225 | StrPtr: u64, | | |
| 226 | StrOffset: usize, | | |
| 227 | LineStrPtr: u64, | | |
| 228 | LocListOffset: u64, | | |
| 229 | RangeListOffset: u64, | | |
| 230 | data16: [16]u8, | | |
| 231 | | | |
| 232 | fn getString(fv: FormValue, di: DwarfInfo) ![]const u8 { | | |
| 233 | switch (fv) { | | |
| 234 | .String => |s| return s, | | |
| 235 | .StrPtr => |off| return di.getString(off), | | |
| 236 | .LineStrPtr => |off| return di.getLineString(off), | | |
| 237 | else => return badDwarf(), | | |
| 238 | } | 207 | } |
| 239 | } | | |
| 240 | | 208 | |
| 241 | fn getUInt(fv: FormValue, comptime U: type) !U { | 209 | fn get(table: *const Table, abbrev_code: u64) ?*const Abbrev { |
| 242 | switch (fv) { | 210 | return for (table.abbrevs) |*abbrev| { |
| 243 | .Const => |c| { | 211 | if (abbrev.code == abbrev_code) break abbrev; |
| 244 | const int = try c.asUnsignedLe(); | 212 | } else null; |
| 245 | return math.cast(U, int) orelse return badDwarf(); | | |
| 246 | }, | | |
| 247 | .SecOffset => |x| return math.cast(U, x) orelse return badDwarf(), | | |
| 248 | else => return badDwarf(), | | |
| 249 | } | 213 | } |
| 250 | } | 214 | }; |
| | 215 | }; |
| 251 | | 216 | |
| 252 | fn getData16(fv: FormValue) ![16]u8 { | 217 | pub const FormValue = union(enum) { |
| | 218 | addr: u64, |
| | 219 | addrx: usize, |
| | 220 | block: []const u8, |
| | 221 | udata: u64, |
| | 222 | data16: *const [16]u8, |
| | 223 | sdata: i64, |
| | 224 | exprloc: []const u8, |
| | 225 | flag: bool, |
| | 226 | sec_offset: u64, |
| | 227 | ref: u64, |
| | 228 | ref_addr: u64, |
| | 229 | string: [:0]const u8, |
| | 230 | strp: u64, |
| | 231 | strx: usize, |
| | 232 | line_strp: u64, |
| | 233 | loclistx: u64, |
| | 234 | rnglistx: u64, |
| | 235 | |
| | 236 | fn getString(fv: FormValue, di: DwarfInfo) ![:0]const u8 { |
| 253 | switch (fv) { | 237 | switch (fv) { |
| 254 | .data16 => |d| return d, | 238 | .string => |s| return s, |
| | 239 | .strp => |off| return di.getString(off), |
| | 240 | .line_strp => |off| return di.getLineString(off), |
| 255 | else => return badDwarf(), | 241 | else => return badDwarf(), |
| 256 | } | 242 | } |
| 257 | } | 243 | } |
| 258 | }; | | |
| 259 | | | |
| 260 | const Constant = struct { | | |
| 261 | payload: u64, | | |
| 262 | signed: bool, | | |
| 263 | | 244 | |
| 264 | fn asUnsignedLe(self: Constant) !u64 { | 245 | fn getUInt(fv: FormValue, comptime U: type) !U { |
| 265 | if (self.signed) return badDwarf(); | 246 | return switch (fv) { |
| 266 | return self.payload; | 247 | inline .udata, |
| | 248 | .sdata, |
| | 249 | .sec_offset, |
| | 250 | => |c| math.cast(U, c) orelse badDwarf(), |
| | 251 | else => badDwarf(), |
| | 252 | }; |
| 267 | } | 253 | } |
| 268 | }; | 254 | }; |
| 269 | | 255 | |
| 270 | const Die = struct { | 256 | const Die = struct { |
| 271 | // Arena for Die's Attr's and FormValue's. | | |
| 272 | arena: std.heap.ArenaAllocator, | | |
| 273 | tag_id: u64, | 257 | tag_id: u64, |
| 274 | has_children: bool, | 258 | has_children: bool, |
| 275 | attrs: std.ArrayListUnmanaged(Attr) = .{}, | 259 | attrs: []Attr, |
| 276 | | 260 | |
| 277 | const Attr = struct { | 261 | const Attr = struct { |
| 278 | id: u64, | 262 | id: u64, |
| ... | @@ -280,12 +264,12 @@ const Die = struct { | ... | @@ -280,12 +264,12 @@ const Die = struct { |
| 280 | }; | 264 | }; |
| 281 | | 265 | |
| 282 | fn deinit(self: *Die, allocator: mem.Allocator) void { | 266 | fn deinit(self: *Die, allocator: mem.Allocator) void { |
| 283 | self.arena.deinit(); | 267 | allocator.free(self.attrs); |
| 284 | self.attrs.deinit(allocator); | 268 | self.* = undefined; |
| 285 | } | 269 | } |
| 286 | | 270 | |
| 287 | fn getAttr(self: *const Die, id: u64) ?*const FormValue { | 271 | fn getAttr(self: *const Die, id: u64) ?*const FormValue { |
| 288 | for (self.attrs.items) |*attr| { | 272 | for (self.attrs) |*attr| { |
| 289 | if (attr.id == id) return &attr.value; | 273 | if (attr.id == id) return &attr.value; |
| 290 | } | 274 | } |
| 291 | return null; | 275 | return null; |
| ... | @@ -299,8 +283,8 @@ const Die = struct { | ... | @@ -299,8 +283,8 @@ const Die = struct { |
| 299 | ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 { | 283 | ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 { |
| 300 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 284 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 301 | return switch (form_value.*) { | 285 | return switch (form_value.*) { |
| 302 | FormValue.Address => |value| value, | 286 | .addr => |value| value, |
| 303 | FormValue.AddrOffset => |index| di.readDebugAddr(compile_unit, index), | 287 | .addrx => |index| di.readDebugAddr(compile_unit, index), |
| 304 | else => error.InvalidDebugInfo, | 288 | else => error.InvalidDebugInfo, |
| 305 | }; | 289 | }; |
| 306 | } | 290 | } |
| ... | @@ -313,7 +297,7 @@ const Die = struct { | ... | @@ -313,7 +297,7 @@ const Die = struct { |
| 313 | fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 { | 297 | fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 { |
| 314 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 298 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 315 | return switch (form_value.*) { | 299 | return switch (form_value.*) { |
| 316 | FormValue.Const => |value| value.asUnsignedLe(), | 300 | .Const => |value| value.asUnsignedLe(), |
| 317 | else => error.InvalidDebugInfo, | 301 | else => error.InvalidDebugInfo, |
| 318 | }; | 302 | }; |
| 319 | } | 303 | } |
| ... | @@ -321,7 +305,7 @@ const Die = struct { | ... | @@ -321,7 +305,7 @@ const Die = struct { |
| 321 | fn getAttrRef(self: *const Die, id: u64) !u64 { | 305 | fn getAttrRef(self: *const Die, id: u64) !u64 { |
| 322 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 306 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 323 | return switch (form_value.*) { | 307 | return switch (form_value.*) { |
| 324 | FormValue.Ref => |value| value, | 308 | .ref => |value| value, |
| 325 | else => error.InvalidDebugInfo, | 309 | else => error.InvalidDebugInfo, |
| 326 | }; | 310 | }; |
| 327 | } | 311 | } |
| ... | @@ -335,24 +319,27 @@ const Die = struct { | ... | @@ -335,24 +319,27 @@ const Die = struct { |
| 335 | ) error{ InvalidDebugInfo, MissingDebugInfo }![]const u8 { | 319 | ) error{ InvalidDebugInfo, MissingDebugInfo }![]const u8 { |
| 336 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 320 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 337 | switch (form_value.*) { | 321 | switch (form_value.*) { |
| 338 | FormValue.String => |value| return value, | 322 | .string => |value| return value, |
| 339 | FormValue.StrPtr => |offset| return di.getString(offset), | 323 | .strp => |offset| return di.getString(offset), |
| 340 | FormValue.StrOffset => |index| { | 324 | .strx => |index| { |
| 341 | const debug_str_offsets = di.section(.debug_str_offsets) orelse return badDwarf(); | 325 | const debug_str_offsets = di.section(.debug_str_offsets) orelse return badDwarf(); |
| 342 | if (compile_unit.str_offsets_base == 0) return badDwarf(); | 326 | if (compile_unit.str_offsets_base == 0) return badDwarf(); |
| 343 | if (compile_unit.is_64) { | 327 | switch (compile_unit.format) { |
| 344 | const byte_offset = compile_unit.str_offsets_base + 8 * index; | 328 | .@"32" => { |
| 345 | if (byte_offset + 8 > debug_str_offsets.len) return badDwarf(); | 329 | const byte_offset = compile_unit.str_offsets_base + 4 * index; |
| 346 | const offset = mem.readInt(u64, debug_str_offsets[byte_offset..][0..8], di.endian); | 330 | if (byte_offset + 4 > debug_str_offsets.len) return badDwarf(); |
| 347 | return getStringGeneric(opt_str, offset); | 331 | const offset = mem.readInt(u32, debug_str_offsets[byte_offset..][0..4], di.endian); |
| 348 | } else { | 332 | return getStringGeneric(opt_str, offset); |
| 349 | const byte_offset = compile_unit.str_offsets_base + 4 * index; | 333 | }, |
| 350 | if (byte_offset + 4 > debug_str_offsets.len) return badDwarf(); | 334 | .@"64" => { |
| 351 | const offset = mem.readInt(u32, debug_str_offsets[byte_offset..][0..4], di.endian); | 335 | const byte_offset = compile_unit.str_offsets_base + 8 * index; |
| 352 | return getStringGeneric(opt_str, offset); | 336 | if (byte_offset + 8 > debug_str_offsets.len) return badDwarf(); |
| | 337 | const offset = mem.readInt(u64, debug_str_offsets[byte_offset..][0..8], di.endian); |
| | 338 | return getStringGeneric(opt_str, offset); |
| | 339 | }, |
| 353 | } | 340 | } |
| 354 | }, | 341 | }, |
| 355 | FormValue.LineStrPtr => |offset| return di.getLineString(offset), | 342 | .line_strp => |offset| return di.getLineString(offset), |
| 356 | else => return badDwarf(), | 343 | else => return badDwarf(), |
| 357 | } | 344 | } |
| 358 | } | 345 | } |
| ... | @@ -458,7 +445,7 @@ const LineNumberProgram = struct { | ... | @@ -458,7 +445,7 @@ const LineNumberProgram = struct { |
| 458 | if (file_entry.dir_index >= self.include_dirs.len) return badDwarf(); | 445 | if (file_entry.dir_index >= self.include_dirs.len) return badDwarf(); |
| 459 | const dir_name = self.include_dirs[file_entry.dir_index].path; | 446 | const dir_name = self.include_dirs[file_entry.dir_index].path; |
| 460 | | 447 | |
| 461 | const file_name = try fs.path.join(allocator, &[_][]const u8{ | 448 | const file_name = try std.fs.path.join(allocator, &[_][]const u8{ |
| 462 | dir_name, file_entry.path, | 449 | dir_name, file_entry.path, |
| 463 | }); | 450 | }); |
| 464 | | 451 | |
| ... | @@ -481,168 +468,97 @@ const LineNumberProgram = struct { | ... | @@ -481,168 +468,97 @@ const LineNumberProgram = struct { |
| 481 | } | 468 | } |
| 482 | }; | 469 | }; |
| 483 | | 470 | |
| 484 | fn readUnitLength(in_stream: anytype, endian: std.builtin.Endian, is_64: *bool) !u64 { | 471 | const UnitHeader = struct { |
| 485 | const first_32_bits = try in_stream.readInt(u32, endian); | 472 | format: Format, |
| 486 | is_64.* = (first_32_bits == 0xffffffff); | 473 | header_length: u4, |
| 487 | if (is_64.*) { | 474 | unit_length: u64, |
| 488 | return in_stream.readInt(u64, endian); | 475 | }; |
| 489 | } else { | 476 | fn readUnitHeader(fbr: *FixedBufferReader) !UnitHeader { |
| 490 | if (first_32_bits >= 0xfffffff0) return badDwarf(); | 477 | return switch (try fbr.readInt(u32)) { |
| 491 | // TODO this cast should not be needed | 478 | 0...0xfffffff0 - 1 => |unit_length| .{ |
| 492 | return @as(u64, first_32_bits); | 479 | .format = .@"32", |
| 493 | } | 480 | .header_length = 4, |
| 494 | } | 481 | .unit_length = unit_length, |
| 495 | | | |
| 496 | // TODO the nosuspends here are workarounds | | |
| 497 | fn readAllocBytes(allocator: mem.Allocator, in_stream: anytype, size: usize) ![]u8 { | | |
| 498 | const buf = try allocator.alloc(u8, size); | | |
| 499 | errdefer allocator.free(buf); | | |
| 500 | if ((try nosuspend in_stream.read(buf)) < size) return error.EndOfFile; | | |
| 501 | return buf; | | |
| 502 | } | | |
| 503 | | | |
| 504 | // TODO the nosuspends here are workarounds | | |
| 505 | fn readAddress(in_stream: anytype, endian: std.builtin.Endian, is_64: bool) !u64 { | | |
| 506 | return nosuspend if (is_64) | | |
| 507 | try in_stream.readInt(u64, endian) | | |
| 508 | else | | |
| 509 | @as(u64, try in_stream.readInt(u32, endian)); | | |
| 510 | } | | |
| 511 | | | |
| 512 | fn parseFormValueBlockLen(allocator: mem.Allocator, in_stream: anytype, size: usize) !FormValue { | | |
| 513 | const buf = try readAllocBytes(allocator, in_stream, size); | | |
| 514 | return FormValue{ .Block = buf }; | | |
| 515 | } | | |
| 516 | | | |
| 517 | // TODO the nosuspends here are workarounds | | |
| 518 | fn parseFormValueBlock(allocator: mem.Allocator, in_stream: anytype, endian: std.builtin.Endian, size: usize) !FormValue { | | |
| 519 | const block_len = try nosuspend in_stream.readVarInt(usize, endian, size); | | |
| 520 | return parseFormValueBlockLen(allocator, in_stream, block_len); | | |
| 521 | } | | |
| 522 | | | |
| 523 | fn parseFormValueConstant(in_stream: anytype, signed: bool, endian: std.builtin.Endian, comptime size: i32) !FormValue { | | |
| 524 | // TODO: Please forgive me, I've worked around zig not properly spilling some intermediate values here. | | |
| 525 | // `nosuspend` should be removed from all the function calls once it is fixed. | | |
| 526 | return FormValue{ | | |
| 527 | .Const = Constant{ | | |
| 528 | .signed = signed, | | |
| 529 | .payload = switch (size) { | | |
| 530 | 1 => try nosuspend in_stream.readInt(u8, endian), | | |
| 531 | 2 => try nosuspend in_stream.readInt(u16, endian), | | |
| 532 | 4 => try nosuspend in_stream.readInt(u32, endian), | | |
| 533 | 8 => try nosuspend in_stream.readInt(u64, endian), | | |
| 534 | -1 => blk: { | | |
| 535 | if (signed) { | | |
| 536 | const x = try nosuspend leb.readILEB128(i64, in_stream); | | |
| 537 | break :blk @as(u64, @bitCast(x)); | | |
| 538 | } else { | | |
| 539 | const x = try nosuspend leb.readULEB128(u64, in_stream); | | |
| 540 | break :blk x; | | |
| 541 | } | | |
| 542 | }, | | |
| 543 | else => @compileError("Invalid size"), | | |
| 544 | }, | | |
| 545 | }, | 482 | }, |
| 546 | }; | 483 | 0xfffffff0...0xffffffff - 1 => badDwarf(), |
| 547 | } | 484 | 0xffffffff => .{ |
| 548 | | 485 | .format = .@"64", |
| 549 | // TODO the nosuspends here are workarounds | 486 | .header_length = 12, |
| 550 | fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32) !FormValue { | 487 | .unit_length = try fbr.readInt(u64), |
| 551 | return FormValue{ | | |
| 552 | .Ref = switch (size) { | | |
| 553 | 1 => try nosuspend in_stream.readInt(u8, endian), | | |
| 554 | 2 => try nosuspend in_stream.readInt(u16, endian), | | |
| 555 | 4 => try nosuspend in_stream.readInt(u32, endian), | | |
| 556 | 8 => try nosuspend in_stream.readInt(u64, endian), | | |
| 557 | -1 => try nosuspend leb.readULEB128(u64, in_stream), | | |
| 558 | else => unreachable, | | |
| 559 | }, | 488 | }, |
| 560 | }; | 489 | }; |
| 561 | } | 490 | } |
| 562 | | 491 | |
| 563 | // TODO the nosuspends here are workarounds | 492 | fn parseFormValue( |
| 564 | fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue { | 493 | fbr: *FixedBufferReader, |
| | 494 | form_id: u64, |
| | 495 | format: Format, |
| | 496 | implicit_const: ?i64, |
| | 497 | ) anyerror!FormValue { |
| 565 | return switch (form_id) { | 498 | return switch (form_id) { |
| 566 | FORM.addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) }, | 499 | FORM.addr => .{ .addr = try fbr.readAddress(switch (@bitSizeOf(usize)) { |
| 567 | FORM.addrx1 => return FormValue{ .AddrOffset = try in_stream.readInt(u8, endian) }, | 500 | 32 => .@"32", |
| 568 | FORM.addrx2 => return FormValue{ .AddrOffset = try in_stream.readInt(u16, endian) }, | 501 | 64 => .@"64", |
| 569 | FORM.addrx3 => return FormValue{ .AddrOffset = try in_stream.readInt(u24, endian) }, | 502 | else => @compileError("unsupported @sizeOf(usize)"), |
| 570 | FORM.addrx4 => return FormValue{ .AddrOffset = try in_stream.readInt(u32, endian) }, | 503 | }) }, |
| 571 | FORM.addrx => return FormValue{ .AddrOffset = try nosuspend leb.readULEB128(usize, in_stream) }, | 504 | FORM.addrx1 => .{ .addrx = try fbr.readInt(u8) }, |
| 572 | | 505 | FORM.addrx2 => .{ .addrx = try fbr.readInt(u16) }, |
| 573 | FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1), | 506 | FORM.addrx3 => .{ .addrx = try fbr.readInt(u24) }, |
| 574 | FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2), | 507 | FORM.addrx4 => .{ .addrx = try fbr.readInt(u32) }, |
| 575 | FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4), | 508 | FORM.addrx => .{ .addrx = try fbr.readUleb128(usize) }, |
| 576 | FORM.block => { | 509 | |
| 577 | const block_len = try nosuspend leb.readULEB128(usize, in_stream); | 510 | FORM.block1, |
| 578 | return parseFormValueBlockLen(allocator, in_stream, block_len); | 511 | FORM.block2, |
| 579 | }, | 512 | FORM.block4, |
| 580 | FORM.data1 => parseFormValueConstant(in_stream, false, endian, 1), | 513 | FORM.block, |
| 581 | FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2), | 514 | => .{ .block = try fbr.readBytes(switch (form_id) { |
| 582 | FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4), | 515 | FORM.block1 => try fbr.readInt(u8), |
| 583 | FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8), | 516 | FORM.block2 => try fbr.readInt(u16), |
| 584 | FORM.data16 => { | 517 | FORM.block4 => try fbr.readInt(u32), |
| 585 | var buf: [16]u8 = undefined; | 518 | FORM.block => try fbr.readUleb128(usize), |
| 586 | if ((try nosuspend in_stream.readAll(&buf)) < 16) return error.EndOfFile; | 519 | else => unreachable, |
| 587 | return FormValue{ .data16 = buf }; | 520 | }) }, |
| 588 | }, | 521 | |
| 589 | FORM.udata, FORM.sdata => { | 522 | FORM.data1 => .{ .udata = try fbr.readInt(u8) }, |
| 590 | const signed = form_id == FORM.sdata; | 523 | FORM.data2 => .{ .udata = try fbr.readInt(u16) }, |
| 591 | return parseFormValueConstant(in_stream, signed, endian, -1); | 524 | FORM.data4 => .{ .udata = try fbr.readInt(u32) }, |
| 592 | }, | 525 | FORM.data8 => .{ .udata = try fbr.readInt(u64) }, |
| 593 | FORM.exprloc => { | 526 | FORM.data16 => .{ .data16 = (try fbr.readBytes(16))[0..16] }, |
| 594 | const size = try nosuspend leb.readULEB128(usize, in_stream); | 527 | FORM.udata => .{ .udata = try fbr.readUleb128(u64) }, |
| 595 | const buf = try readAllocBytes(allocator, in_stream, size); | 528 | FORM.sdata => .{ .sdata = try fbr.readIleb128(i64) }, |
| 596 | return FormValue{ .ExprLoc = buf }; | 529 | FORM.exprloc => .{ .exprloc = try fbr.readBytes(try fbr.readUleb128(usize)) }, |
| 597 | }, | 530 | FORM.flag => .{ .flag = (try fbr.readByte()) != 0 }, |
| 598 | FORM.flag => FormValue{ .Flag = (try nosuspend in_stream.readByte()) != 0 }, | 531 | FORM.flag_present => .{ .flag = true }, |
| 599 | FORM.flag_present => FormValue{ .Flag = true }, | 532 | FORM.sec_offset => .{ .sec_offset = try fbr.readAddress(format) }, |
| 600 | FORM.sec_offset => FormValue{ .SecOffset = try readAddress(in_stream, endian, is_64) }, | 533 | |
| 601 | | 534 | FORM.ref1 => .{ .ref = try fbr.readInt(u8) }, |
| 602 | FORM.ref1 => parseFormValueRef(in_stream, endian, 1), | 535 | FORM.ref2 => .{ .ref = try fbr.readInt(u16) }, |
| 603 | FORM.ref2 => parseFormValueRef(in_stream, endian, 2), | 536 | FORM.ref4 => .{ .ref = try fbr.readInt(u32) }, |
| 604 | FORM.ref4 => parseFormValueRef(in_stream, endian, 4), | 537 | FORM.ref8 => .{ .ref = try fbr.readInt(u64) }, |
| 605 | FORM.ref8 => parseFormValueRef(in_stream, endian, 8), | 538 | FORM.ref_udata => .{ .ref = try fbr.readUleb128(u64) }, |
| 606 | FORM.ref_udata => parseFormValueRef(in_stream, endian, -1), | 539 | |
| 607 | | 540 | FORM.ref_addr => .{ .ref_addr = try fbr.readAddress(format) }, |
| 608 | FORM.ref_addr => FormValue{ .RefAddr = try readAddress(in_stream, endian, is_64) }, | 541 | FORM.ref_sig8 => .{ .ref = try fbr.readInt(u64) }, |
| 609 | FORM.ref_sig8 => FormValue{ .Ref = try nosuspend in_stream.readInt(u64, endian) }, | 542 | |
| 610 | | 543 | FORM.string => .{ .string = try fbr.readBytesTo(0) }, |
| 611 | FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) }, | 544 | FORM.strp => .{ .strp = try fbr.readAddress(format) }, |
| 612 | FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) }, | 545 | FORM.strx1 => .{ .strx = try fbr.readInt(u8) }, |
| 613 | FORM.strx1 => return FormValue{ .StrOffset = try in_stream.readInt(u8, endian) }, | 546 | FORM.strx2 => .{ .strx = try fbr.readInt(u16) }, |
| 614 | FORM.strx2 => return FormValue{ .StrOffset = try in_stream.readInt(u16, endian) }, | 547 | FORM.strx3 => .{ .strx = try fbr.readInt(u24) }, |
| 615 | FORM.strx3 => return FormValue{ .StrOffset = try in_stream.readInt(u24, endian) }, | 548 | FORM.strx4 => .{ .strx = try fbr.readInt(u32) }, |
| 616 | FORM.strx4 => return FormValue{ .StrOffset = try in_stream.readInt(u32, endian) }, | 549 | FORM.strx => .{ .strx = try fbr.readUleb128(usize) }, |
| 617 | FORM.strx => return FormValue{ .StrOffset = try nosuspend leb.readULEB128(usize, in_stream) }, | 550 | FORM.line_strp => .{ .line_strp = try fbr.readAddress(format) }, |
| 618 | FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) }, | 551 | FORM.indirect => parseFormValue(fbr, try fbr.readUleb128(u64), format, implicit_const), |
| 619 | FORM.indirect => { | 552 | FORM.implicit_const => .{ .sdata = implicit_const orelse return badDwarf() }, |
| 620 | const child_form_id = try nosuspend leb.readULEB128(u64, in_stream); | 553 | FORM.loclistx => .{ .loclistx = try fbr.readUleb128(u64) }, |
| 621 | if (true) { | 554 | FORM.rnglistx => .{ .rnglistx = try fbr.readUleb128(u64) }, |
| 622 | return parseFormValue(allocator, in_stream, child_form_id, endian, is_64); | | |
| 623 | } | | |
| 624 | const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64)); | | |
| 625 | const frame = try allocator.create(F); | | |
| 626 | defer allocator.destroy(frame); | | |
| 627 | return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 }); | | |
| 628 | }, | | |
| 629 | FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } }, | | |
| 630 | FORM.loclistx => return FormValue{ .LocListOffset = try nosuspend leb.readULEB128(u64, in_stream) }, | | |
| 631 | FORM.rnglistx => return FormValue{ .RangeListOffset = try nosuspend leb.readULEB128(u64, in_stream) }, | | |
| 632 | else => { | 555 | else => { |
| 633 | //std.debug.print("unrecognized form id: {x}\n", .{form_id}); | 556 | //debug.print("unrecognized form id: {x}\n", .{form_id}); |
| 634 | return badDwarf(); | 557 | return badDwarf(); |
| 635 | }, | 558 | }, |
| 636 | }; | 559 | }; |
| 637 | } | 560 | } |
| 638 | | 561 | |
| 639 | fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { | | |
| 640 | for (abbrev_table.items) |*table_entry| { | | |
| 641 | if (table_entry.abbrev_code == abbrev_code) return table_entry; | | |
| 642 | } | | |
| 643 | return null; | | |
| 644 | } | | |
| 645 | | | |
| 646 | pub const DwarfSection = enum { | 562 | pub const DwarfSection = enum { |
| 647 | debug_info, | 563 | debug_info, |
| 648 | debug_abbrev, | 564 | debug_abbrev, |
| ... | @@ -690,7 +606,7 @@ pub const DwarfInfo = struct { | ... | @@ -690,7 +606,7 @@ pub const DwarfInfo = struct { |
| 690 | is_macho: bool, | 606 | is_macho: bool, |
| 691 | | 607 | |
| 692 | // Filled later by the initializer | 608 | // Filled later by the initializer |
| 693 | abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, | 609 | abbrev_table_list: std.ArrayListUnmanaged(Abbrev.Table) = .{}, |
| 694 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, | 610 | compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 695 | func_list: std.ArrayListUnmanaged(Func) = .{}, | 611 | func_list: std.ArrayListUnmanaged(Func) = .{}, |
| 696 | | 612 | |
| ... | @@ -713,17 +629,17 @@ pub const DwarfInfo = struct { | ... | @@ -713,17 +629,17 @@ pub const DwarfInfo = struct { |
| 713 | if (opt_section) |s| if (s.owned) allocator.free(s.data); | 629 | if (opt_section) |s| if (s.owned) allocator.free(s.data); |
| 714 | } | 630 | } |
| 715 | for (di.abbrev_table_list.items) |*abbrev| { | 631 | for (di.abbrev_table_list.items) |*abbrev| { |
| 716 | abbrev.deinit(); | 632 | abbrev.deinit(allocator); |
| 717 | } | 633 | } |
| 718 | di.abbrev_table_list.deinit(allocator); | 634 | di.abbrev_table_list.deinit(allocator); |
| 719 | for (di.compile_unit_list.items) |*cu| { | 635 | for (di.compile_unit_list.items) |*cu| { |
| 720 | cu.die.deinit(allocator); | 636 | cu.die.deinit(allocator); |
| 721 | allocator.destroy(cu.die); | | |
| 722 | } | 637 | } |
| 723 | di.compile_unit_list.deinit(allocator); | 638 | di.compile_unit_list.deinit(allocator); |
| 724 | di.func_list.deinit(allocator); | 639 | di.func_list.deinit(allocator); |
| 725 | di.cie_map.deinit(allocator); | 640 | di.cie_map.deinit(allocator); |
| 726 | di.fde_list.deinit(allocator); | 641 | di.fde_list.deinit(allocator); |
| | 642 | di.* = undefined; |
| 727 | } | 643 | } |
| 728 | | 644 | |
| 729 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { | 645 | pub fn getSymbolName(di: *DwarfInfo, address: u64) ?[]const u8 { |
| ... | @@ -739,102 +655,125 @@ pub const DwarfInfo = struct { | ... | @@ -739,102 +655,125 @@ pub const DwarfInfo = struct { |
| 739 | } | 655 | } |
| 740 | | 656 | |
| 741 | fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void { | 657 | fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 742 | var stream = io.fixedBufferStream(di.section(.debug_info).?); | 658 | var fbr: FixedBufferReader = .{ .buf = di.section(.debug_info).?, .endian = di.endian }; |
| 743 | const in = stream.reader(); | | |
| 744 | const seekable = stream.seekableStream(); | | |
| 745 | var this_unit_offset: u64 = 0; | 659 | var this_unit_offset: u64 = 0; |
| 746 | | 660 | |
| 747 | var tmp_arena = std.heap.ArenaAllocator.init(allocator); | 661 | while (this_unit_offset < fbr.buf.len) { |
| 748 | defer tmp_arena.deinit(); | 662 | try fbr.seekTo(this_unit_offset); |
| 749 | const arena = tmp_arena.allocator(); | | |
| 750 | | 663 | |
| 751 | while (this_unit_offset < try seekable.getEndPos()) { | 664 | const unit_header = try readUnitHeader(&fbr); |
| 752 | try seekable.seekTo(this_unit_offset); | 665 | if (unit_header.unit_length == 0) return; |
| | 666 | const next_offset = unit_header.header_length + unit_header.unit_length; |
| 753 | | 667 | |
| 754 | var is_64: bool = undefined; | 668 | const version = try fbr.readInt(u16); |
| 755 | const unit_length = try readUnitLength(in, di.endian, &is_64); | | |
| 756 | if (unit_length == 0) return; | | |
| 757 | const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); | | |
| 758 | | | |
| 759 | const version = try in.readInt(u16, di.endian); | | |
| 760 | if (version < 2 or version > 5) return badDwarf(); | 669 | if (version < 2 or version > 5) return badDwarf(); |
| 761 | | 670 | |
| 762 | var address_size: u8 = undefined; | 671 | var address_size: u8 = undefined; |
| 763 | var debug_abbrev_offset: u64 = undefined; | 672 | var debug_abbrev_offset: u64 = undefined; |
| 764 | if (version >= 5) { | 673 | if (version >= 5) { |
| 765 | const unit_type = try in.readInt(u8, di.endian); | 674 | const unit_type = try fbr.readInt(u8); |
| 766 | if (unit_type != UT.compile) return badDwarf(); | 675 | if (unit_type != UT.compile) return badDwarf(); |
| 767 | address_size = try in.readByte(); | 676 | address_size = try fbr.readByte(); |
| 768 | debug_abbrev_offset = if (is_64) | 677 | debug_abbrev_offset = try fbr.readAddress(unit_header.format); |
| 769 | try in.readInt(u64, di.endian) | | |
| 770 | else | | |
| 771 | try in.readInt(u32, di.endian); | | |
| 772 | } else { | 678 | } else { |
| 773 | debug_abbrev_offset = if (is_64) | 679 | debug_abbrev_offset = try fbr.readAddress(unit_header.format); |
| 774 | try in.readInt(u64, di.endian) | 680 | address_size = try fbr.readByte(); |
| 775 | else | | |
| 776 | try in.readInt(u32, di.endian); | | |
| 777 | address_size = try in.readByte(); | | |
| 778 | } | 681 | } |
| 779 | if (address_size != @sizeOf(usize)) return badDwarf(); | 682 | if (address_size != @sizeOf(usize)) return badDwarf(); |
| 780 | | 683 | |
| 781 | const compile_unit_pos = try seekable.getPos(); | | |
| 782 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); | 684 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 783 | | 685 | |
| 784 | try seekable.seekTo(compile_unit_pos); | 686 | var max_attrs: usize = 0; |
| | 687 | var zig_padding_abbrev_code: u7 = 0; |
| | 688 | for (abbrev_table.abbrevs) |abbrev| { |
| | 689 | max_attrs = @max(max_attrs, abbrev.attrs.len); |
| | 690 | if (math.cast(u7, abbrev.code)) |code| { |
| | 691 | if (abbrev.tag_id == TAG.ZIG_padding and |
| | 692 | !abbrev.has_children and |
| | 693 | abbrev.attrs.len == 0) |
| | 694 | { |
| | 695 | zig_padding_abbrev_code = code; |
| | 696 | } |
| | 697 | } |
| | 698 | } |
| | 699 | const attrs_buf = try allocator.alloc(Die.Attr, max_attrs * 3); |
| | 700 | defer allocator.free(attrs_buf); |
| | 701 | var attrs_bufs: [3][]Die.Attr = undefined; |
| | 702 | for (&attrs_bufs, 0..) |*buf, index| buf.* = attrs_buf[index * max_attrs ..][0..max_attrs]; |
| 785 | | 703 | |
| 786 | const next_unit_pos = this_unit_offset + next_offset; | 704 | const next_unit_pos = this_unit_offset + next_offset; |
| 787 | | 705 | |
| 788 | var compile_unit: CompileUnit = undefined; | 706 | var compile_unit: CompileUnit = .{ |
| | 707 | .version = version, |
| | 708 | .format = unit_header.format, |
| | 709 | .die = undefined, |
| | 710 | .pc_range = null, |
| 789 | | 711 | |
| 790 | while ((try seekable.getPos()) < next_unit_pos) { | 712 | .str_offsets_base = 0, |
| 791 | var die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue; | 713 | .addr_base = 0, |
| 792 | const after_die_offset = try seekable.getPos(); | 714 | .rnglists_base = 0, |
| | 715 | .loclists_base = 0, |
| | 716 | .frame_base = null, |
| | 717 | }; |
| | 718 | |
| | 719 | while (true) { |
| | 720 | fbr.pos = mem.indexOfNonePos(u8, fbr.buf, fbr.pos, &.{ |
| | 721 | zig_padding_abbrev_code, 0, |
| | 722 | }) orelse fbr.buf.len; |
| | 723 | if (fbr.pos >= next_unit_pos) break; |
| | 724 | var die_obj = (try parseDie( |
| | 725 | &fbr, |
| | 726 | attrs_bufs[0], |
| | 727 | abbrev_table, |
| | 728 | unit_header.format, |
| | 729 | )) orelse continue; |
| 793 | | 730 | |
| 794 | switch (die_obj.tag_id) { | 731 | switch (die_obj.tag_id) { |
| 795 | TAG.compile_unit => { | 732 | TAG.compile_unit => { |
| 796 | compile_unit = .{ | 733 | compile_unit.die = die_obj; |
| 797 | .version = version, | 734 | compile_unit.die.attrs = attrs_bufs[1][0..die_obj.attrs.len]; |
| 798 | .is_64 = is_64, | 735 | @memcpy(compile_unit.die.attrs, die_obj.attrs); |
| 799 | .die = &die_obj, | 736 | |
| 800 | .pc_range = null, | 737 | compile_unit.str_offsets_base = if (die_obj.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0; |
| 801 | | 738 | compile_unit.addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0; |
| 802 | .str_offsets_base = if (die_obj.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0, | 739 | compile_unit.rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0; |
| 803 | .addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0, | 740 | compile_unit.loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0; |
| 804 | .rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0, | 741 | compile_unit.frame_base = die_obj.getAttr(AT.frame_base); |
| 805 | .loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0, | | |
| 806 | .frame_base = die_obj.getAttr(AT.frame_base), | | |
| 807 | }; | | |
| 808 | }, | 742 | }, |
| 809 | TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => { | 743 | TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => { |
| 810 | const fn_name = x: { | 744 | const fn_name = x: { |
| 811 | var depth: i32 = 3; | | |
| 812 | var this_die_obj = die_obj; | 745 | var this_die_obj = die_obj; |
| 813 | // Prevent endless loops | 746 | // Prevent endless loops |
| 814 | while (depth > 0) : (depth -= 1) { | 747 | for (0..3) |_| { |
| 815 | if (this_die_obj.getAttr(AT.name)) |_| { | 748 | if (this_die_obj.getAttr(AT.name)) |_| { |
| 816 | break :x try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit); | 749 | break :x try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit); |
| 817 | } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| { | 750 | } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| { |
| | 751 | const after_die_offset = fbr.pos; |
| | 752 | defer fbr.pos = after_die_offset; |
| | 753 | |
| 818 | // Follow the DIE it points to and repeat | 754 | // Follow the DIE it points to and repeat |
| 819 | const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin); | 755 | const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin); |
| 820 | if (ref_offset > next_offset) return badDwarf(); | 756 | if (ref_offset > next_offset) return badDwarf(); |
| 821 | try seekable.seekTo(this_unit_offset + ref_offset); | 757 | try fbr.seekTo(this_unit_offset + ref_offset); |
| 822 | this_die_obj = (try di.parseDie( | 758 | this_die_obj = (try parseDie( |
| 823 | arena, | 759 | &fbr, |
| 824 | in, | 760 | attrs_bufs[2], |
| 825 | abbrev_table, | 761 | abbrev_table, |
| 826 | is_64, | 762 | unit_header.format, |
| 827 | )) orelse return badDwarf(); | 763 | )) orelse return badDwarf(); |
| 828 | } else if (this_die_obj.getAttr(AT.specification)) |_| { | 764 | } else if (this_die_obj.getAttr(AT.specification)) |_| { |
| | 765 | const after_die_offset = fbr.pos; |
| | 766 | defer fbr.pos = after_die_offset; |
| | 767 | |
| 829 | // Follow the DIE it points to and repeat | 768 | // Follow the DIE it points to and repeat |
| 830 | const ref_offset = try this_die_obj.getAttrRef(AT.specification); | 769 | const ref_offset = try this_die_obj.getAttrRef(AT.specification); |
| 831 | if (ref_offset > next_offset) return badDwarf(); | 770 | if (ref_offset > next_offset) return badDwarf(); |
| 832 | try seekable.seekTo(this_unit_offset + ref_offset); | 771 | try fbr.seekTo(this_unit_offset + ref_offset); |
| 833 | this_die_obj = (try di.parseDie( | 772 | this_die_obj = (try parseDie( |
| 834 | arena, | 773 | &fbr, |
| 835 | in, | 774 | attrs_bufs[2], |
| 836 | abbrev_table, | 775 | abbrev_table, |
| 837 | is_64, | 776 | unit_header.format, |
| 838 | )) orelse return badDwarf(); | 777 | )) orelse return badDwarf(); |
| 839 | } else { | 778 | } else { |
| 840 | break :x null; | 779 | break :x null; |
| ... | @@ -847,15 +786,12 @@ pub const DwarfInfo = struct { | ... | @@ -847,15 +786,12 @@ pub const DwarfInfo = struct { |
| 847 | var range_added = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: { | 786 | var range_added = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: { |
| 848 | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { | 787 | if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { |
| 849 | const pc_end = switch (high_pc_value.*) { | 788 | const pc_end = switch (high_pc_value.*) { |
| 850 | FormValue.Address => |value| value, | 789 | .addr => |value| value, |
| 851 | FormValue.Const => |value| b: { | 790 | .udata => |offset| low_pc + offset, |
| 852 | const offset = try value.asUnsignedLe(); | | |
| 853 | break :b (low_pc + offset); | | |
| 854 | }, | | |
| 855 | else => return badDwarf(), | 791 | else => return badDwarf(), |
| 856 | }; | 792 | }; |
| 857 | | 793 | |
| 858 | try di.func_list.append(allocator, Func{ | 794 | try di.func_list.append(allocator, .{ |
| 859 | .name = fn_name, | 795 | .name = fn_name, |
| 860 | .pc_range = .{ | 796 | .pc_range = .{ |
| 861 | .start = low_pc, | 797 | .start = low_pc, |
| ... | @@ -880,7 +816,7 @@ pub const DwarfInfo = struct { | ... | @@ -880,7 +816,7 @@ pub const DwarfInfo = struct { |
| 880 | | 816 | |
| 881 | while (try iter.next()) |range| { | 817 | while (try iter.next()) |range| { |
| 882 | range_added = true; | 818 | range_added = true; |
| 883 | try di.func_list.append(allocator, Func{ | 819 | try di.func_list.append(allocator, .{ |
| 884 | .name = fn_name, | 820 | .name = fn_name, |
| 885 | .pc_range = .{ | 821 | .pc_range = .{ |
| 886 | .start = range.start_addr, | 822 | .start = range.start_addr, |
| ... | @@ -891,7 +827,7 @@ pub const DwarfInfo = struct { | ... | @@ -891,7 +827,7 @@ pub const DwarfInfo = struct { |
| 891 | } | 827 | } |
| 892 | | 828 | |
| 893 | if (fn_name != null and !range_added) { | 829 | if (fn_name != null and !range_added) { |
| 894 | try di.func_list.append(allocator, Func{ | 830 | try di.func_list.append(allocator, .{ |
| 895 | .name = fn_name, | 831 | .name = fn_name, |
| 896 | .pc_range = null, | 832 | .pc_range = null, |
| 897 | }); | 833 | }); |
| ... | @@ -899,8 +835,6 @@ pub const DwarfInfo = struct { | ... | @@ -899,8 +835,6 @@ pub const DwarfInfo = struct { |
| 899 | }, | 835 | }, |
| 900 | else => {}, | 836 | else => {}, |
| 901 | } | 837 | } |
| 902 | | | |
| 903 | try seekable.seekTo(after_die_offset); | | |
| 904 | } | 838 | } |
| 905 | | 839 | |
| 906 | this_unit_offset += next_offset; | 840 | this_unit_offset += next_offset; |
| ... | @@ -908,56 +842,57 @@ pub const DwarfInfo = struct { | ... | @@ -908,56 +842,57 @@ pub const DwarfInfo = struct { |
| 908 | } | 842 | } |
| 909 | | 843 | |
| 910 | fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void { | 844 | fn scanAllCompileUnits(di: *DwarfInfo, allocator: mem.Allocator) !void { |
| 911 | var stream = io.fixedBufferStream(di.section(.debug_info).?); | 845 | var fbr: FixedBufferReader = .{ .buf = di.section(.debug_info).?, .endian = di.endian }; |
| 912 | const in = stream.reader(); | | |
| 913 | const seekable = stream.seekableStream(); | | |
| 914 | var this_unit_offset: u64 = 0; | 846 | var this_unit_offset: u64 = 0; |
| 915 | | 847 | |
| 916 | while (this_unit_offset < try seekable.getEndPos()) { | 848 | var attrs_buf = std.ArrayList(Die.Attr).init(allocator); |
| 917 | try seekable.seekTo(this_unit_offset); | 849 | defer attrs_buf.deinit(); |
| | 850 | |
| | 851 | while (this_unit_offset < fbr.buf.len) { |
| | 852 | try fbr.seekTo(this_unit_offset); |
| 918 | | 853 | |
| 919 | var is_64: bool = undefined; | 854 | const unit_header = try readUnitHeader(&fbr); |
| 920 | const unit_length = try readUnitLength(in, di.endian, &is_64); | 855 | if (unit_header.unit_length == 0) return; |
| 921 | if (unit_length == 0) return; | 856 | const next_offset = unit_header.header_length + unit_header.unit_length; |
| 922 | const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); | | |
| 923 | | 857 | |
| 924 | const version = try in.readInt(u16, di.endian); | 858 | const version = try fbr.readInt(u16); |
| 925 | if (version < 2 or version > 5) return badDwarf(); | 859 | if (version < 2 or version > 5) return badDwarf(); |
| 926 | | 860 | |
| 927 | var address_size: u8 = undefined; | 861 | var address_size: u8 = undefined; |
| 928 | var debug_abbrev_offset: u64 = undefined; | 862 | var debug_abbrev_offset: u64 = undefined; |
| 929 | if (version >= 5) { | 863 | if (version >= 5) { |
| 930 | const unit_type = try in.readInt(u8, di.endian); | 864 | const unit_type = try fbr.readInt(u8); |
| 931 | if (unit_type != UT.compile) return badDwarf(); | 865 | if (unit_type != UT.compile) return badDwarf(); |
| 932 | address_size = try in.readByte(); | 866 | address_size = try fbr.readByte(); |
| 933 | debug_abbrev_offset = if (is_64) | 867 | debug_abbrev_offset = try fbr.readAddress(unit_header.format); |
| 934 | try in.readInt(u64, di.endian) | | |
| 935 | else | | |
| 936 | try in.readInt(u32, di.endian); | | |
| 937 | } else { | 868 | } else { |
| 938 | debug_abbrev_offset = if (is_64) | 869 | debug_abbrev_offset = try fbr.readAddress(unit_header.format); |
| 939 | try in.readInt(u64, di.endian) | 870 | address_size = try fbr.readByte(); |
| 940 | else | | |
| 941 | try in.readInt(u32, di.endian); | | |
| 942 | address_size = try in.readByte(); | | |
| 943 | } | 871 | } |
| 944 | if (address_size != @sizeOf(usize)) return badDwarf(); | 872 | if (address_size != @sizeOf(usize)) return badDwarf(); |
| 945 | | 873 | |
| 946 | const compile_unit_pos = try seekable.getPos(); | | |
| 947 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); | 874 | const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); |
| 948 | | 875 | |
| 949 | try seekable.seekTo(compile_unit_pos); | 876 | var max_attrs: usize = 0; |
| | 877 | for (abbrev_table.abbrevs) |abbrev| { |
| | 878 | max_attrs = @max(max_attrs, abbrev.attrs.len); |
| | 879 | } |
| | 880 | try attrs_buf.resize(max_attrs); |
| 950 | | 881 | |
| 951 | const compile_unit_die = try allocator.create(Die); | 882 | var compile_unit_die = (try parseDie( |
| 952 | errdefer allocator.destroy(compile_unit_die); | 883 | &fbr, |
| 953 | compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse | 884 | attrs_buf.items, |
| 954 | return badDwarf(); | 885 | abbrev_table, |
| | 886 | unit_header.format, |
| | 887 | )) orelse return badDwarf(); |
| 955 | | 888 | |
| 956 | if (compile_unit_die.tag_id != TAG.compile_unit) return badDwarf(); | 889 | if (compile_unit_die.tag_id != TAG.compile_unit) return badDwarf(); |
| 957 | | 890 | |
| | 891 | compile_unit_die.attrs = try allocator.dupe(Die.Attr, compile_unit_die.attrs); |
| | 892 | |
| 958 | var compile_unit: CompileUnit = .{ | 893 | var compile_unit: CompileUnit = .{ |
| 959 | .version = version, | 894 | .version = version, |
| 960 | .is_64 = is_64, | 895 | .format = unit_header.format, |
| 961 | .pc_range = null, | 896 | .pc_range = null, |
| 962 | .die = compile_unit_die, | 897 | .die = compile_unit_die, |
| 963 | .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0, | 898 | .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0, |
| ... | @@ -971,11 +906,8 @@ pub const DwarfInfo = struct { | ... | @@ -971,11 +906,8 @@ pub const DwarfInfo = struct { |
| 971 | if (compile_unit_die.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| { | 906 | if (compile_unit_die.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| { |
| 972 | if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| { | 907 | if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| { |
| 973 | const pc_end = switch (high_pc_value.*) { | 908 | const pc_end = switch (high_pc_value.*) { |
| 974 | FormValue.Address => |value| value, | 909 | .addr => |value| value, |
| 975 | FormValue.Const => |value| b: { | 910 | .udata => |offset| low_pc + offset, |
| 976 | const offset = try value.asUnsignedLe(); | | |
| 977 | break :b (low_pc + offset); | | |
| 978 | }, | | |
| 979 | else => return badDwarf(), | 911 | else => return badDwarf(), |
| 980 | }; | 912 | }; |
| 981 | break :x PcRange{ | 913 | break :x PcRange{ |
| ... | @@ -1002,40 +934,39 @@ pub const DwarfInfo = struct { | ... | @@ -1002,40 +934,39 @@ pub const DwarfInfo = struct { |
| 1002 | section_type: DwarfSection, | 934 | section_type: DwarfSection, |
| 1003 | di: *const DwarfInfo, | 935 | di: *const DwarfInfo, |
| 1004 | compile_unit: *const CompileUnit, | 936 | compile_unit: *const CompileUnit, |
| 1005 | stream: io.FixedBufferStream([]const u8), | 937 | fbr: FixedBufferReader, |
| 1006 | | 938 | |
| 1007 | pub fn init(ranges_value: *const FormValue, di: *const DwarfInfo, compile_unit: *const CompileUnit) !@This() { | 939 | pub fn init(ranges_value: *const FormValue, di: *const DwarfInfo, compile_unit: *const CompileUnit) !@This() { |
| 1008 | const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges; | 940 | const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges; |
| 1009 | const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo; | 941 | const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo; |
| 1010 | | 942 | |
| 1011 | const ranges_offset = switch (ranges_value.*) { | 943 | const ranges_offset = switch (ranges_value.*) { |
| 1012 | .SecOffset => |off| off, | 944 | .sec_offset, .udata => |off| off, |
| 1013 | .Const => |c| try c.asUnsignedLe(), | 945 | .rnglistx => |idx| off: { |
| 1014 | .RangeListOffset => |idx| off: { | 946 | switch (compile_unit.format) { |
| 1015 | if (compile_unit.is_64) { | 947 | .@"32" => { |
| 1016 | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 8 * idx)); | 948 | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 4 * idx)); |
| 1017 | if (offset_loc + 8 > debug_ranges.len) return badDwarf(); | 949 | if (offset_loc + 4 > debug_ranges.len) return badDwarf(); |
| 1018 | const offset = mem.readInt(u64, debug_ranges[offset_loc..][0..8], di.endian); | 950 | const offset = mem.readInt(u32, debug_ranges[offset_loc..][0..4], di.endian); |
| 1019 | break :off compile_unit.rnglists_base + offset; | 951 | break :off compile_unit.rnglists_base + offset; |
| 1020 | } else { | 952 | }, |
| 1021 | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 4 * idx)); | 953 | .@"64" => { |
| 1022 | if (offset_loc + 4 > debug_ranges.len) return badDwarf(); | 954 | const offset_loc = @as(usize, @intCast(compile_unit.rnglists_base + 8 * idx)); |
| 1023 | const offset = mem.readInt(u32, debug_ranges[offset_loc..][0..4], di.endian); | 955 | if (offset_loc + 8 > debug_ranges.len) return badDwarf(); |
| 1024 | break :off compile_unit.rnglists_base + offset; | 956 | const offset = mem.readInt(u64, debug_ranges[offset_loc..][0..8], di.endian); |
| | 957 | break :off compile_unit.rnglists_base + offset; |
| | 958 | }, |
| 1025 | } | 959 | } |
| 1026 | }, | 960 | }, |
| 1027 | else => return badDwarf(), | 961 | else => return badDwarf(), |
| 1028 | }; | 962 | }; |
| 1029 | | 963 | |
| 1030 | var stream = io.fixedBufferStream(debug_ranges); | | |
| 1031 | try stream.seekTo(ranges_offset); | | |
| 1032 | | | |
| 1033 | // All the addresses in the list are relative to the value | 964 | // All the addresses in the list are relative to the value |
| 1034 | // specified by DW_AT.low_pc or to some other value encoded | 965 | // specified by DW_AT.low_pc or to some other value encoded |
| 1035 | // in the list itself. | 966 | // in the list itself. |
| 1036 | // If no starting value is specified use zero. | 967 | // If no starting value is specified use zero. |
| 1037 | const base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) { | 968 | const base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) { |
| 1038 | error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135 | 969 | error.MissingDebugInfo => 0, |
| 1039 | else => return err, | 970 | else => return err, |
| 1040 | }; | 971 | }; |
| 1041 | | 972 | |
| ... | @@ -1044,28 +975,31 @@ pub const DwarfInfo = struct { | ... | @@ -1044,28 +975,31 @@ pub const DwarfInfo = struct { |
| 1044 | .section_type = section_type, | 975 | .section_type = section_type, |
| 1045 | .di = di, | 976 | .di = di, |
| 1046 | .compile_unit = compile_unit, | 977 | .compile_unit = compile_unit, |
| 1047 | .stream = stream, | 978 | .fbr = .{ |
| | 979 | .buf = debug_ranges, |
| | 980 | .pos = math.cast(usize, ranges_offset) orelse return badDwarf(), |
| | 981 | .endian = di.endian, |
| | 982 | }, |
| 1048 | }; | 983 | }; |
| 1049 | } | 984 | } |
| 1050 | | 985 | |
| 1051 | // Returns the next range in the list, or null if the end was reached. | 986 | // Returns the next range in the list, or null if the end was reached. |
| 1052 | pub fn next(self: *@This()) !?struct { start_addr: u64, end_addr: u64 } { | 987 | pub fn next(self: *@This()) !?struct { start_addr: u64, end_addr: u64 } { |
| 1053 | const in = self.stream.reader(); | | |
| 1054 | switch (self.section_type) { | 988 | switch (self.section_type) { |
| 1055 | .debug_rnglists => { | 989 | .debug_rnglists => { |
| 1056 | const kind = try in.readByte(); | 990 | const kind = try self.fbr.readByte(); |
| 1057 | switch (kind) { | 991 | switch (kind) { |
| 1058 | RLE.end_of_list => return null, | 992 | RLE.end_of_list => return null, |
| 1059 | RLE.base_addressx => { | 993 | RLE.base_addressx => { |
| 1060 | const index = try leb.readULEB128(usize, in); | 994 | const index = try self.fbr.readUleb128(usize); |
| 1061 | self.base_address = try self.di.readDebugAddr(self.compile_unit.*, index); | 995 | self.base_address = try self.di.readDebugAddr(self.compile_unit.*, index); |
| 1062 | return try self.next(); | 996 | return try self.next(); |
| 1063 | }, | 997 | }, |
| 1064 | RLE.startx_endx => { | 998 | RLE.startx_endx => { |
| 1065 | const start_index = try leb.readULEB128(usize, in); | 999 | const start_index = try self.fbr.readUleb128(usize); |
| 1066 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); | 1000 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); |
| 1067 | | 1001 | |
| 1068 | const end_index = try leb.readULEB128(usize, in); | 1002 | const end_index = try self.fbr.readUleb128(usize); |
| 1069 | const end_addr = try self.di.readDebugAddr(self.compile_unit.*, end_index); | 1003 | const end_addr = try self.di.readDebugAddr(self.compile_unit.*, end_index); |
| 1070 | | 1004 | |
| 1071 | return .{ | 1005 | return .{ |
| ... | @@ -1074,10 +1008,10 @@ pub const DwarfInfo = struct { | ... | @@ -1074,10 +1008,10 @@ pub const DwarfInfo = struct { |
| 1074 | }; | 1008 | }; |
| 1075 | }, | 1009 | }, |
| 1076 | RLE.startx_length => { | 1010 | RLE.startx_length => { |
| 1077 | const start_index = try leb.readULEB128(usize, in); | 1011 | const start_index = try self.fbr.readUleb128(usize); |
| 1078 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); | 1012 | const start_addr = try self.di.readDebugAddr(self.compile_unit.*, start_index); |
| 1079 | | 1013 | |
| 1080 | const len = try leb.readULEB128(usize, in); | 1014 | const len = try self.fbr.readUleb128(usize); |
| 1081 | const end_addr = start_addr + len; | 1015 | const end_addr = start_addr + len; |
| 1082 | | 1016 | |
| 1083 | return .{ | 1017 | return .{ |
| ... | @@ -1086,8 +1020,8 @@ pub const DwarfInfo = struct { | ... | @@ -1086,8 +1020,8 @@ pub const DwarfInfo = struct { |
| 1086 | }; | 1020 | }; |
| 1087 | }, | 1021 | }, |
| 1088 | RLE.offset_pair => { | 1022 | RLE.offset_pair => { |
| 1089 | const start_addr = try leb.readULEB128(usize, in); | 1023 | const start_addr = try self.fbr.readUleb128(usize); |
| 1090 | const end_addr = try leb.readULEB128(usize, in); | 1024 | const end_addr = try self.fbr.readUleb128(usize); |
| 1091 | | 1025 | |
| 1092 | // This is the only kind that uses the base address | 1026 | // This is the only kind that uses the base address |
| 1093 | return .{ | 1027 | return .{ |
| ... | @@ -1096,12 +1030,12 @@ pub const DwarfInfo = struct { | ... | @@ -1096,12 +1030,12 @@ pub const DwarfInfo = struct { |
| 1096 | }; | 1030 | }; |
| 1097 | }, | 1031 | }, |
| 1098 | RLE.base_address => { | 1032 | RLE.base_address => { |
| 1099 | self.base_address = try in.readInt(usize, self.di.endian); | 1033 | self.base_address = try self.fbr.readInt(usize); |
| 1100 | return try self.next(); | 1034 | return try self.next(); |
| 1101 | }, | 1035 | }, |
| 1102 | RLE.start_end => { | 1036 | RLE.start_end => { |
| 1103 | const start_addr = try in.readInt(usize, self.di.endian); | 1037 | const start_addr = try self.fbr.readInt(usize); |
| 1104 | const end_addr = try in.readInt(usize, self.di.endian); | 1038 | const end_addr = try self.fbr.readInt(usize); |
| 1105 | | 1039 | |
| 1106 | return .{ | 1040 | return .{ |
| 1107 | .start_addr = start_addr, | 1041 | .start_addr = start_addr, |
| ... | @@ -1109,8 +1043,8 @@ pub const DwarfInfo = struct { | ... | @@ -1109,8 +1043,8 @@ pub const DwarfInfo = struct { |
| 1109 | }; | 1043 | }; |
| 1110 | }, | 1044 | }, |
| 1111 | RLE.start_length => { | 1045 | RLE.start_length => { |
| 1112 | const start_addr = try in.readInt(usize, self.di.endian); | 1046 | const start_addr = try self.fbr.readInt(usize); |
| 1113 | const len = try leb.readULEB128(usize, in); | 1047 | const len = try self.fbr.readUleb128(usize); |
| 1114 | const end_addr = start_addr + len; | 1048 | const end_addr = start_addr + len; |
| 1115 | | 1049 | |
| 1116 | return .{ | 1050 | return .{ |
| ... | @@ -1122,8 +1056,8 @@ pub const DwarfInfo = struct { | ... | @@ -1122,8 +1056,8 @@ pub const DwarfInfo = struct { |
| 1122 | } | 1056 | } |
| 1123 | }, | 1057 | }, |
| 1124 | .debug_ranges => { | 1058 | .debug_ranges => { |
| 1125 | const start_addr = try in.readInt(usize, self.di.endian); | 1059 | const start_addr = try self.fbr.readInt(usize); |
| 1126 | const end_addr = try in.readInt(usize, self.di.endian); | 1060 | const end_addr = try self.fbr.readInt(usize); |
| 1127 | if (start_addr == 0 and end_addr == 0) return null; | 1061 | if (start_addr == 0 and end_addr == 0) return null; |
| 1128 | | 1062 | |
| 1129 | // This entry selects a new value for the base address | 1063 | // This entry selects a new value for the base address |
| ... | @@ -1160,93 +1094,96 @@ pub const DwarfInfo = struct { | ... | @@ -1160,93 +1094,96 @@ pub const DwarfInfo = struct { |
| 1160 | | 1094 | |
| 1161 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, | 1095 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 1162 | /// seeks in the stream and parses it. | 1096 | /// seeks in the stream and parses it. |
| 1163 | fn getAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, abbrev_offset: u64) !*const AbbrevTable { | 1097 | fn getAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, abbrev_offset: u64) !*const Abbrev.Table { |
| 1164 | for (di.abbrev_table_list.items) |*header| { | 1098 | for (di.abbrev_table_list.items) |*table| { |
| 1165 | if (header.offset == abbrev_offset) { | 1099 | if (table.offset == abbrev_offset) { |
| 1166 | return &header.table; | 1100 | return table; |
| 1167 | } | 1101 | } |
| 1168 | } | 1102 | } |
| 1169 | try di.abbrev_table_list.append(allocator, AbbrevTableHeader{ | 1103 | try di.abbrev_table_list.append( |
| 1170 | .offset = abbrev_offset, | 1104 | allocator, |
| 1171 | .table = try di.parseAbbrevTable(allocator, abbrev_offset), | 1105 | try di.parseAbbrevTable(allocator, abbrev_offset), |
| 1172 | }); | 1106 | ); |
| 1173 | return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1].table; | 1107 | return &di.abbrev_table_list.items[di.abbrev_table_list.items.len - 1]; |
| 1174 | } | 1108 | } |
| 1175 | | 1109 | |
| 1176 | fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !AbbrevTable { | 1110 | fn parseAbbrevTable(di: *DwarfInfo, allocator: mem.Allocator, offset: u64) !Abbrev.Table { |
| 1177 | var stream = io.fixedBufferStream(di.section(.debug_abbrev).?); | 1111 | var fbr: FixedBufferReader = .{ |
| 1178 | const in = stream.reader(); | 1112 | .buf = di.section(.debug_abbrev).?, |
| 1179 | const seekable = stream.seekableStream(); | 1113 | .pos = math.cast(usize, offset) orelse return badDwarf(), |
| | 1114 | .endian = di.endian, |
| | 1115 | }; |
| 1180 | | 1116 | |
| 1181 | try seekable.seekTo(offset); | 1117 | var abbrevs = std.ArrayList(Abbrev).init(allocator); |
| 1182 | var result = AbbrevTable.init(allocator); | 1118 | defer { |
| 1183 | errdefer { | 1119 | for (abbrevs.items) |*abbrev| { |
| 1184 | for (result.items) |*entry| { | 1120 | abbrev.deinit(allocator); |
| 1185 | entry.attrs.deinit(); | | |
| 1186 | } | 1121 | } |
| 1187 | result.deinit(); | 1122 | abbrevs.deinit(); |
| 1188 | } | 1123 | } |
| 1189 | | 1124 | |
| | 1125 | var attrs = std.ArrayList(Abbrev.Attr).init(allocator); |
| | 1126 | defer attrs.deinit(); |
| | 1127 | |
| 1190 | while (true) { | 1128 | while (true) { |
| 1191 | const abbrev_code = try leb.readULEB128(u64, in); | 1129 | const code = try fbr.readUleb128(u64); |
| 1192 | if (abbrev_code == 0) return result; | 1130 | if (code == 0) break; |
| 1193 | try result.append(AbbrevTableEntry{ | 1131 | const tag_id = try fbr.readUleb128(u64); |
| 1194 | .abbrev_code = abbrev_code, | 1132 | const has_children = (try fbr.readByte()) == CHILDREN.yes; |
| 1195 | .tag_id = try leb.readULEB128(u64, in), | | |
| 1196 | .has_children = (try in.readByte()) == CHILDREN.yes, | | |
| 1197 | .attrs = std.ArrayList(AbbrevAttr).init(allocator), | | |
| 1198 | }); | | |
| 1199 | const attrs = &result.items[result.items.len - 1].attrs; | | |
| 1200 | | 1133 | |
| 1201 | while (true) { | 1134 | while (true) { |
| 1202 | const attr_id = try leb.readULEB128(u64, in); | 1135 | const attr_id = try fbr.readUleb128(u64); |
| 1203 | const form_id = try leb.readULEB128(u64, in); | 1136 | const form_id = try fbr.readUleb128(u64); |
| 1204 | if (attr_id == 0 and form_id == 0) break; | 1137 | if (attr_id == 0 and form_id == 0) break; |
| 1205 | // DW_FORM_implicit_const stores its value immediately after the attribute pair :( | 1138 | try attrs.append(.{ |
| 1206 | const payload = if (form_id == FORM.implicit_const) try leb.readILEB128(i64, in) else undefined; | 1139 | .id = attr_id, |
| 1207 | try attrs.append(AbbrevAttr{ | | |
| 1208 | .attr_id = attr_id, | | |
| 1209 | .form_id = form_id, | 1140 | .form_id = form_id, |
| 1210 | .payload = payload, | 1141 | .payload = switch (form_id) { |
| | 1142 | FORM.implicit_const => try fbr.readIleb128(i64), |
| | 1143 | else => undefined, |
| | 1144 | }, |
| 1211 | }); | 1145 | }); |
| 1212 | } | 1146 | } |
| | 1147 | |
| | 1148 | try abbrevs.append(.{ |
| | 1149 | .code = code, |
| | 1150 | .tag_id = tag_id, |
| | 1151 | .has_children = has_children, |
| | 1152 | .attrs = try attrs.toOwnedSlice(), |
| | 1153 | }); |
| 1213 | } | 1154 | } |
| | 1155 | |
| | 1156 | return .{ |
| | 1157 | .offset = offset, |
| | 1158 | .abbrevs = try abbrevs.toOwnedSlice(), |
| | 1159 | }; |
| 1214 | } | 1160 | } |
| 1215 | | 1161 | |
| 1216 | fn parseDie( | 1162 | fn parseDie( |
| 1217 | di: *DwarfInfo, | 1163 | fbr: *FixedBufferReader, |
| 1218 | allocator: mem.Allocator, | 1164 | attrs_buf: []Die.Attr, |
| 1219 | in_stream: anytype, | 1165 | abbrev_table: *const Abbrev.Table, |
| 1220 | abbrev_table: *const AbbrevTable, | 1166 | format: Format, |
| 1221 | is_64: bool, | | |
| 1222 | ) !?Die { | 1167 | ) !?Die { |
| 1223 | const abbrev_code = try leb.readULEB128(u64, in_stream); | 1168 | const abbrev_code = try fbr.readUleb128(u64); |
| 1224 | if (abbrev_code == 0) return null; | 1169 | if (abbrev_code == 0) return null; |
| 1225 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return badDwarf(); | 1170 | const table_entry = abbrev_table.get(abbrev_code) orelse return badDwarf(); |
| 1226 | | 1171 | |
| 1227 | var result = Die{ | 1172 | const attrs = attrs_buf[0..table_entry.attrs.len]; |
| 1228 | // Lives as long as the Die. | 1173 | for (attrs, table_entry.attrs) |*result_attr, attr| result_attr.* = Die.Attr{ |
| 1229 | .arena = std.heap.ArenaAllocator.init(allocator), | 1174 | .id = attr.id, |
| | 1175 | .value = try parseFormValue( |
| | 1176 | fbr, |
| | 1177 | attr.form_id, |
| | 1178 | format, |
| | 1179 | attr.payload, |
| | 1180 | ), |
| | 1181 | }; |
| | 1182 | return .{ |
| 1230 | .tag_id = table_entry.tag_id, | 1183 | .tag_id = table_entry.tag_id, |
| 1231 | .has_children = table_entry.has_children, | 1184 | .has_children = table_entry.has_children, |
| | 1185 | .attrs = attrs, |
| 1232 | }; | 1186 | }; |
| 1233 | try result.attrs.resize(allocator, table_entry.attrs.items.len); | | |
| 1234 | for (table_entry.attrs.items, 0..) |attr, i| { | | |
| 1235 | result.attrs.items[i] = Die.Attr{ | | |
| 1236 | .id = attr.attr_id, | | |
| 1237 | .value = try parseFormValue( | | |
| 1238 | result.arena.allocator(), | | |
| 1239 | in_stream, | | |
| 1240 | attr.form_id, | | |
| 1241 | di.endian, | | |
| 1242 | is_64, | | |
| 1243 | ), | | |
| 1244 | }; | | |
| 1245 | if (attr.form_id == FORM.implicit_const) { | | |
| 1246 | result.attrs.items[i].value.Const.payload = @as(u64, @bitCast(attr.payload)); | | |
| 1247 | } | | |
| 1248 | } | | |
| 1249 | return result; | | |
| 1250 | } | 1187 | } |
| 1251 | | 1188 | |
| 1252 | pub fn getLineNumberInfo( | 1189 | pub fn getLineNumberInfo( |
| ... | @@ -1255,50 +1192,47 @@ pub const DwarfInfo = struct { | ... | @@ -1255,50 +1192,47 @@ pub const DwarfInfo = struct { |
| 1255 | compile_unit: CompileUnit, | 1192 | compile_unit: CompileUnit, |
| 1256 | target_address: u64, | 1193 | target_address: u64, |
| 1257 | ) !debug.LineInfo { | 1194 | ) !debug.LineInfo { |
| 1258 | var stream = io.fixedBufferStream(di.section(.debug_line).?); | | |
| 1259 | const in = stream.reader(); | | |
| 1260 | const seekable = stream.seekableStream(); | | |
| 1261 | | | |
| 1262 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit); | 1195 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.section(.debug_line_str), compile_unit); |
| 1263 | const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); | 1196 | const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); |
| 1264 | | 1197 | |
| 1265 | try seekable.seekTo(line_info_offset); | 1198 | var fbr: FixedBufferReader = .{ .buf = di.section(.debug_line).?, .endian = di.endian }; |
| | 1199 | try fbr.seekTo(line_info_offset); |
| 1266 | | 1200 | |
| 1267 | var is_64: bool = undefined; | 1201 | const unit_header = try readUnitHeader(&fbr); |
| 1268 | const unit_length = try readUnitLength(in, di.endian, &is_64); | 1202 | if (unit_header.unit_length == 0) return missingDwarf(); |
| 1269 | if (unit_length == 0) { | 1203 | const next_offset = unit_header.header_length + unit_header.unit_length; |
| 1270 | return missingDwarf(); | | |
| 1271 | } | | |
| 1272 | const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); | | |
| 1273 | | 1204 | |
| 1274 | const version = try in.readInt(u16, di.endian); | 1205 | const version = try fbr.readInt(u16); |
| 1275 | if (version < 2) return badDwarf(); | 1206 | if (version < 2) return badDwarf(); |
| 1276 | | 1207 | |
| 1277 | var addr_size: u8 = if (is_64) 8 else 4; | 1208 | var addr_size: u8 = switch (unit_header.format) { |
| | 1209 | .@"32" => 4, |
| | 1210 | .@"64" => 8, |
| | 1211 | }; |
| 1278 | var seg_size: u8 = 0; | 1212 | var seg_size: u8 = 0; |
| 1279 | if (version >= 5) { | 1213 | if (version >= 5) { |
| 1280 | addr_size = try in.readByte(); | 1214 | addr_size = try fbr.readByte(); |
| 1281 | seg_size = try in.readByte(); | 1215 | seg_size = try fbr.readByte(); |
| 1282 | } | 1216 | } |
| 1283 | | 1217 | |
| 1284 | const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); | 1218 | const prologue_length = try fbr.readAddress(unit_header.format); |
| 1285 | const prog_start_offset = (try seekable.getPos()) + prologue_length; | 1219 | const prog_start_offset = fbr.pos + prologue_length; |
| 1286 | | 1220 | |
| 1287 | const minimum_instruction_length = try in.readByte(); | 1221 | const minimum_instruction_length = try fbr.readByte(); |
| 1288 | if (minimum_instruction_length == 0) return badDwarf(); | 1222 | if (minimum_instruction_length == 0) return badDwarf(); |
| 1289 | | 1223 | |
| 1290 | if (version >= 4) { | 1224 | if (version >= 4) { |
| 1291 | // maximum_operations_per_instruction | 1225 | // maximum_operations_per_instruction |
| 1292 | _ = try in.readByte(); | 1226 | _ = try fbr.readByte(); |
| 1293 | } | 1227 | } |
| 1294 | | 1228 | |
| 1295 | const default_is_stmt = (try in.readByte()) != 0; | 1229 | const default_is_stmt = (try fbr.readByte()) != 0; |
| 1296 | const line_base = try in.readByteSigned(); | 1230 | const line_base = try fbr.readByteSigned(); |
| 1297 | | 1231 | |
| 1298 | const line_range = try in.readByte(); | 1232 | const line_range = try fbr.readByte(); |
| 1299 | if (line_range == 0) return badDwarf(); | 1233 | if (line_range == 0) return badDwarf(); |
| 1300 | | 1234 | |
| 1301 | const opcode_base = try in.readByte(); | 1235 | const opcode_base = try fbr.readByte(); |
| 1302 | | 1236 | |
| 1303 | const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1); | 1237 | const standard_opcode_lengths = try allocator.alloc(u8, opcode_base - 1); |
| 1304 | defer allocator.free(standard_opcode_lengths); | 1238 | defer allocator.free(standard_opcode_lengths); |
| ... | @@ -1306,33 +1240,31 @@ pub const DwarfInfo = struct { | ... | @@ -1306,33 +1240,31 @@ pub const DwarfInfo = struct { |
| 1306 | { | 1240 | { |
| 1307 | var i: usize = 0; | 1241 | var i: usize = 0; |
| 1308 | while (i < opcode_base - 1) : (i += 1) { | 1242 | while (i < opcode_base - 1) : (i += 1) { |
| 1309 | standard_opcode_lengths[i] = try in.readByte(); | 1243 | standard_opcode_lengths[i] = try fbr.readByte(); |
| 1310 | } | 1244 | } |
| 1311 | } | 1245 | } |
| 1312 | | 1246 | |
| 1313 | var tmp_arena = std.heap.ArenaAllocator.init(allocator); | 1247 | var include_directories = std.ArrayList(FileEntry).init(allocator); |
| 1314 | defer tmp_arena.deinit(); | 1248 | defer include_directories.deinit(); |
| 1315 | const arena = tmp_arena.allocator(); | 1249 | var file_entries = std.ArrayList(FileEntry).init(allocator); |
| 1316 | | 1250 | defer file_entries.deinit(); |
| 1317 | var include_directories = std.ArrayList(FileEntry).init(arena); | | |
| 1318 | var file_entries = std.ArrayList(FileEntry).init(arena); | | |
| 1319 | | 1251 | |
| 1320 | if (version < 5) { | 1252 | if (version < 5) { |
| 1321 | try include_directories.append(.{ .path = compile_unit_cwd }); | 1253 | try include_directories.append(.{ .path = compile_unit_cwd }); |
| 1322 | | 1254 | |
| 1323 | while (true) { | 1255 | while (true) { |
| 1324 | const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); | 1256 | const dir = try fbr.readBytesTo(0); |
| 1325 | if (dir.len == 0) break; | 1257 | if (dir.len == 0) break; |
| 1326 | try include_directories.append(.{ .path = dir }); | 1258 | try include_directories.append(.{ .path = dir }); |
| 1327 | } | 1259 | } |
| 1328 | | 1260 | |
| 1329 | while (true) { | 1261 | while (true) { |
| 1330 | const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); | 1262 | const file_name = try fbr.readBytesTo(0); |
| 1331 | if (file_name.len == 0) break; | 1263 | if (file_name.len == 0) break; |
| 1332 | const dir_index = try leb.readULEB128(u32, in); | 1264 | const dir_index = try fbr.readUleb128(u32); |
| 1333 | const mtime = try leb.readULEB128(u64, in); | 1265 | const mtime = try fbr.readUleb128(u64); |
| 1334 | const size = try leb.readULEB128(u64, in); | 1266 | const size = try fbr.readUleb128(u64); |
| 1335 | try file_entries.append(FileEntry{ | 1267 | try file_entries.append(.{ |
| 1336 | .path = file_name, | 1268 | .path = file_name, |
| 1337 | .dir_index = dir_index, | 1269 | .dir_index = dir_index, |
| 1338 | .mtime = mtime, | 1270 | .mtime = mtime, |
| ... | @@ -1346,16 +1278,16 @@ pub const DwarfInfo = struct { | ... | @@ -1346,16 +1278,16 @@ pub const DwarfInfo = struct { |
| 1346 | }; | 1278 | }; |
| 1347 | { | 1279 | { |
| 1348 | var dir_ent_fmt_buf: [10]FileEntFmt = undefined; | 1280 | var dir_ent_fmt_buf: [10]FileEntFmt = undefined; |
| 1349 | const directory_entry_format_count = try in.readByte(); | 1281 | const directory_entry_format_count = try fbr.readByte(); |
| 1350 | if (directory_entry_format_count > dir_ent_fmt_buf.len) return badDwarf(); | 1282 | if (directory_entry_format_count > dir_ent_fmt_buf.len) return badDwarf(); |
| 1351 | for (dir_ent_fmt_buf[0..directory_entry_format_count]) |*ent_fmt| { | 1283 | for (dir_ent_fmt_buf[0..directory_entry_format_count]) |*ent_fmt| { |
| 1352 | ent_fmt.* = .{ | 1284 | ent_fmt.* = .{ |
| 1353 | .content_type_code = try leb.readULEB128(u8, in), | 1285 | .content_type_code = try fbr.readUleb128(u8), |
| 1354 | .form_code = try leb.readULEB128(u16, in), | 1286 | .form_code = try fbr.readUleb128(u16), |
| 1355 | }; | 1287 | }; |
| 1356 | } | 1288 | } |
| 1357 | | 1289 | |
| 1358 | const directories_count = try leb.readULEB128(usize, in); | 1290 | const directories_count = try fbr.readUleb128(usize); |
| 1359 | try include_directories.ensureUnusedCapacity(directories_count); | 1291 | try include_directories.ensureUnusedCapacity(directories_count); |
| 1360 | { | 1292 | { |
| 1361 | var i: usize = 0; | 1293 | var i: usize = 0; |
| ... | @@ -1363,18 +1295,20 @@ pub const DwarfInfo = struct { | ... | @@ -1363,18 +1295,20 @@ pub const DwarfInfo = struct { |
| 1363 | var e: FileEntry = .{ .path = &.{} }; | 1295 | var e: FileEntry = .{ .path = &.{} }; |
| 1364 | for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| { | 1296 | for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| { |
| 1365 | const form_value = try parseFormValue( | 1297 | const form_value = try parseFormValue( |
| 1366 | arena, | 1298 | &fbr, |
| 1367 | in, | | |
| 1368 | ent_fmt.form_code, | 1299 | ent_fmt.form_code, |
| 1369 | di.endian, | 1300 | unit_header.format, |
| 1370 | is_64, | 1301 | null, |
| 1371 | ); | 1302 | ); |
| 1372 | switch (ent_fmt.content_type_code) { | 1303 | switch (ent_fmt.content_type_code) { |
| 1373 | LNCT.path => e.path = try form_value.getString(di.*), | 1304 | LNCT.path => e.path = try form_value.getString(di.*), |
| 1374 | LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), | 1305 | LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), |
| 1375 | LNCT.timestamp => e.mtime = try form_value.getUInt(u64), | 1306 | LNCT.timestamp => e.mtime = try form_value.getUInt(u64), |
| 1376 | LNCT.size => e.size = try form_value.getUInt(u64), | 1307 | LNCT.size => e.size = try form_value.getUInt(u64), |
| 1377 | LNCT.MD5 => e.md5 = try form_value.getData16(), | 1308 | LNCT.MD5 => e.md5 = switch (form_value) { |
| | 1309 | .data16 => |data16| data16.*, |
| | 1310 | else => return badDwarf(), |
| | 1311 | }, |
| 1378 | else => continue, | 1312 | else => continue, |
| 1379 | } | 1313 | } |
| 1380 | } | 1314 | } |
| ... | @@ -1384,16 +1318,16 @@ pub const DwarfInfo = struct { | ... | @@ -1384,16 +1318,16 @@ pub const DwarfInfo = struct { |
| 1384 | } | 1318 | } |
| 1385 | | 1319 | |
| 1386 | var file_ent_fmt_buf: [10]FileEntFmt = undefined; | 1320 | var file_ent_fmt_buf: [10]FileEntFmt = undefined; |
| 1387 | const file_name_entry_format_count = try in.readByte(); | 1321 | const file_name_entry_format_count = try fbr.readByte(); |
| 1388 | if (file_name_entry_format_count > file_ent_fmt_buf.len) return badDwarf(); | 1322 | if (file_name_entry_format_count > file_ent_fmt_buf.len) return badDwarf(); |
| 1389 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| { | 1323 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| { |
| 1390 | ent_fmt.* = .{ | 1324 | ent_fmt.* = .{ |
| 1391 | .content_type_code = try leb.readULEB128(u8, in), | 1325 | .content_type_code = try fbr.readUleb128(u8), |
| 1392 | .form_code = try leb.readULEB128(u16, in), | 1326 | .form_code = try fbr.readUleb128(u16), |
| 1393 | }; | 1327 | }; |
| 1394 | } | 1328 | } |
| 1395 | | 1329 | |
| 1396 | const file_names_count = try leb.readULEB128(usize, in); | 1330 | const file_names_count = try fbr.readUleb128(usize); |
| 1397 | try file_entries.ensureUnusedCapacity(file_names_count); | 1331 | try file_entries.ensureUnusedCapacity(file_names_count); |
| 1398 | { | 1332 | { |
| 1399 | var i: usize = 0; | 1333 | var i: usize = 0; |
| ... | @@ -1401,18 +1335,20 @@ pub const DwarfInfo = struct { | ... | @@ -1401,18 +1335,20 @@ pub const DwarfInfo = struct { |
| 1401 | var e: FileEntry = .{ .path = &.{} }; | 1335 | var e: FileEntry = .{ .path = &.{} }; |
| 1402 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| { | 1336 | for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| { |
| 1403 | const form_value = try parseFormValue( | 1337 | const form_value = try parseFormValue( |
| 1404 | arena, | 1338 | &fbr, |
| 1405 | in, | | |
| 1406 | ent_fmt.form_code, | 1339 | ent_fmt.form_code, |
| 1407 | di.endian, | 1340 | unit_header.format, |
| 1408 | is_64, | 1341 | null, |
| 1409 | ); | 1342 | ); |
| 1410 | switch (ent_fmt.content_type_code) { | 1343 | switch (ent_fmt.content_type_code) { |
| 1411 | LNCT.path => e.path = try form_value.getString(di.*), | 1344 | LNCT.path => e.path = try form_value.getString(di.*), |
| 1412 | LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), | 1345 | LNCT.directory_index => e.dir_index = try form_value.getUInt(u32), |
| 1413 | LNCT.timestamp => e.mtime = try form_value.getUInt(u64), | 1346 | LNCT.timestamp => e.mtime = try form_value.getUInt(u64), |
| 1414 | LNCT.size => e.size = try form_value.getUInt(u64), | 1347 | LNCT.size => e.size = try form_value.getUInt(u64), |
| 1415 | LNCT.MD5 => e.md5 = try form_value.getData16(), | 1348 | LNCT.MD5 => e.md5 = switch (form_value) { |
| | 1349 | .data16 => |data16| data16.*, |
| | 1350 | else => return badDwarf(), |
| | 1351 | }, |
| 1416 | else => continue, | 1352 | else => continue, |
| 1417 | } | 1353 | } |
| 1418 | } | 1354 | } |
| ... | @@ -1428,17 +1364,17 @@ pub const DwarfInfo = struct { | ... | @@ -1428,17 +1364,17 @@ pub const DwarfInfo = struct { |
| 1428 | version, | 1364 | version, |
| 1429 | ); | 1365 | ); |
| 1430 | | 1366 | |
| 1431 | try seekable.seekTo(prog_start_offset); | 1367 | try fbr.seekTo(prog_start_offset); |
| 1432 | | 1368 | |
| 1433 | const next_unit_pos = line_info_offset + next_offset; | 1369 | const next_unit_pos = line_info_offset + next_offset; |
| 1434 | | 1370 | |
| 1435 | while ((try seekable.getPos()) < next_unit_pos) { | 1371 | while (fbr.pos < next_unit_pos) { |
| 1436 | const opcode = try in.readByte(); | 1372 | const opcode = try fbr.readByte(); |
| 1437 | | 1373 | |
| 1438 | if (opcode == LNS.extended_op) { | 1374 | if (opcode == LNS.extended_op) { |
| 1439 | const op_size = try leb.readULEB128(u64, in); | 1375 | const op_size = try fbr.readUleb128(u64); |
| 1440 | if (op_size < 1) return badDwarf(); | 1376 | if (op_size < 1) return badDwarf(); |
| 1441 | const sub_op = try in.readByte(); | 1377 | const sub_op = try fbr.readByte(); |
| 1442 | switch (sub_op) { | 1378 | switch (sub_op) { |
| 1443 | LNE.end_sequence => { | 1379 | LNE.end_sequence => { |
| 1444 | prog.end_sequence = true; | 1380 | prog.end_sequence = true; |
| ... | @@ -1446,25 +1382,22 @@ pub const DwarfInfo = struct { | ... | @@ -1446,25 +1382,22 @@ pub const DwarfInfo = struct { |
| 1446 | prog.reset(); | 1382 | prog.reset(); |
| 1447 | }, | 1383 | }, |
| 1448 | LNE.set_address => { | 1384 | LNE.set_address => { |
| 1449 | const addr = try in.readInt(usize, di.endian); | 1385 | const addr = try fbr.readInt(usize); |
| 1450 | prog.address = addr; | 1386 | prog.address = addr; |
| 1451 | }, | 1387 | }, |
| 1452 | LNE.define_file => { | 1388 | LNE.define_file => { |
| 1453 | const path = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); | 1389 | const path = try fbr.readBytesTo(0); |
| 1454 | const dir_index = try leb.readULEB128(u32, in); | 1390 | const dir_index = try fbr.readUleb128(u32); |
| 1455 | const mtime = try leb.readULEB128(u64, in); | 1391 | const mtime = try fbr.readUleb128(u64); |
| 1456 | const size = try leb.readULEB128(u64, in); | 1392 | const size = try fbr.readUleb128(u64); |
| 1457 | try file_entries.append(FileEntry{ | 1393 | try file_entries.append(.{ |
| 1458 | .path = path, | 1394 | .path = path, |
| 1459 | .dir_index = dir_index, | 1395 | .dir_index = dir_index, |
| 1460 | .mtime = mtime, | 1396 | .mtime = mtime, |
| 1461 | .size = size, | 1397 | .size = size, |
| 1462 | }); | 1398 | }); |
| 1463 | }, | 1399 | }, |
| 1464 | else => { | 1400 | else => try fbr.seekForward(op_size - 1), |
| 1465 | const fwd_amt = math.cast(isize, op_size - 1) orelse return badDwarf(); | | |
| 1466 | try seekable.seekBy(fwd_amt); | | |
| 1467 | }, | | |
| 1468 | } | 1401 | } |
| 1469 | } else if (opcode >= opcode_base) { | 1402 | } else if (opcode >= opcode_base) { |
| 1470 | // special opcodes | 1403 | // special opcodes |
| ... | @@ -1482,19 +1415,19 @@ pub const DwarfInfo = struct { | ... | @@ -1482,19 +1415,19 @@ pub const DwarfInfo = struct { |
| 1482 | prog.basic_block = false; | 1415 | prog.basic_block = false; |
| 1483 | }, | 1416 | }, |
| 1484 | LNS.advance_pc => { | 1417 | LNS.advance_pc => { |
| 1485 | const arg = try leb.readULEB128(usize, in); | 1418 | const arg = try fbr.readUleb128(usize); |
| 1486 | prog.address += arg * minimum_instruction_length; | 1419 | prog.address += arg * minimum_instruction_length; |
| 1487 | }, | 1420 | }, |
| 1488 | LNS.advance_line => { | 1421 | LNS.advance_line => { |
| 1489 | const arg = try leb.readILEB128(i64, in); | 1422 | const arg = try fbr.readIleb128(i64); |
| 1490 | prog.line += arg; | 1423 | prog.line += arg; |
| 1491 | }, | 1424 | }, |
| 1492 | LNS.set_file => { | 1425 | LNS.set_file => { |
| 1493 | const arg = try leb.readULEB128(usize, in); | 1426 | const arg = try fbr.readUleb128(usize); |
| 1494 | prog.file = arg; | 1427 | prog.file = arg; |
| 1495 | }, | 1428 | }, |
| 1496 | LNS.set_column => { | 1429 | LNS.set_column => { |
| 1497 | const arg = try leb.readULEB128(u64, in); | 1430 | const arg = try fbr.readUleb128(u64); |
| 1498 | prog.column = arg; | 1431 | prog.column = arg; |
| 1499 | }, | 1432 | }, |
| 1500 | LNS.negate_stmt => { | 1433 | LNS.negate_stmt => { |
| ... | @@ -1508,14 +1441,13 @@ pub const DwarfInfo = struct { | ... | @@ -1508,14 +1441,13 @@ pub const DwarfInfo = struct { |
| 1508 | prog.address += inc_addr; | 1441 | prog.address += inc_addr; |
| 1509 | }, | 1442 | }, |
| 1510 | LNS.fixed_advance_pc => { | 1443 | LNS.fixed_advance_pc => { |
| 1511 | const arg = try in.readInt(u16, di.endian); | 1444 | const arg = try fbr.readInt(u16); |
| 1512 | prog.address += arg; | 1445 | prog.address += arg; |
| 1513 | }, | 1446 | }, |
| 1514 | LNS.set_prologue_end => {}, | 1447 | LNS.set_prologue_end => {}, |
| 1515 | else => { | 1448 | else => { |
| 1516 | if (opcode - 1 >= standard_opcode_lengths.len) return badDwarf(); | 1449 | if (opcode - 1 >= standard_opcode_lengths.len) return badDwarf(); |
| 1517 | const len_bytes = standard_opcode_lengths[opcode - 1]; | 1450 | try fbr.seekForward(standard_opcode_lengths[opcode - 1]); |
| 1518 | try seekable.seekBy(len_bytes); | | |
| 1519 | }, | 1451 | }, |
| 1520 | } | 1452 | } |
| 1521 | } | 1453 | } |
| ... | @@ -1524,11 +1456,11 @@ pub const DwarfInfo = struct { | ... | @@ -1524,11 +1456,11 @@ pub const DwarfInfo = struct { |
| 1524 | return missingDwarf(); | 1456 | return missingDwarf(); |
| 1525 | } | 1457 | } |
| 1526 | | 1458 | |
| 1527 | fn getString(di: DwarfInfo, offset: u64) ![]const u8 { | 1459 | fn getString(di: DwarfInfo, offset: u64) ![:0]const u8 { |
| 1528 | return getStringGeneric(di.section(.debug_str), offset); | 1460 | return getStringGeneric(di.section(.debug_str), offset); |
| 1529 | } | 1461 | } |
| 1530 | | 1462 | |
| 1531 | fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 { | 1463 | fn getLineString(di: DwarfInfo, offset: u64) ![:0]const u8 { |
| 1532 | return getStringGeneric(di.section(.debug_line_str), offset); | 1464 | return getStringGeneric(di.section(.debug_line_str), offset); |
| 1533 | } | 1465 | } |
| 1534 | | 1466 | |
| ... | @@ -1564,38 +1496,37 @@ pub const DwarfInfo = struct { | ... | @@ -1564,38 +1496,37 @@ pub const DwarfInfo = struct { |
| 1564 | /// of FDEs is built for binary searching during unwinding. | 1496 | /// of FDEs is built for binary searching during unwinding. |
| 1565 | pub fn scanAllUnwindInfo(di: *DwarfInfo, allocator: mem.Allocator, base_address: usize) !void { | 1497 | pub fn scanAllUnwindInfo(di: *DwarfInfo, allocator: mem.Allocator, base_address: usize) !void { |
| 1566 | if (di.section(.eh_frame_hdr)) |eh_frame_hdr| blk: { | 1498 | if (di.section(.eh_frame_hdr)) |eh_frame_hdr| blk: { |
| 1567 | var stream = io.fixedBufferStream(eh_frame_hdr); | 1499 | var fbr: FixedBufferReader = .{ .buf = eh_frame_hdr, .endian = native_endian }; |
| 1568 | const reader = stream.reader(); | | |
| 1569 | | 1500 | |
| 1570 | const version = try reader.readByte(); | 1501 | const version = try fbr.readByte(); |
| 1571 | if (version != 1) break :blk; | 1502 | if (version != 1) break :blk; |
| 1572 | | 1503 | |
| 1573 | const eh_frame_ptr_enc = try reader.readByte(); | 1504 | const eh_frame_ptr_enc = try fbr.readByte(); |
| 1574 | if (eh_frame_ptr_enc == EH.PE.omit) break :blk; | 1505 | if (eh_frame_ptr_enc == EH.PE.omit) break :blk; |
| 1575 | const fde_count_enc = try reader.readByte(); | 1506 | const fde_count_enc = try fbr.readByte(); |
| 1576 | if (fde_count_enc == EH.PE.omit) break :blk; | 1507 | if (fde_count_enc == EH.PE.omit) break :blk; |
| 1577 | const table_enc = try reader.readByte(); | 1508 | const table_enc = try fbr.readByte(); |
| 1578 | if (table_enc == EH.PE.omit) break :blk; | 1509 | if (table_enc == EH.PE.omit) break :blk; |
| 1579 | | 1510 | |
| 1580 | const eh_frame_ptr = std.math.cast(usize, try readEhPointer(reader, eh_frame_ptr_enc, @sizeOf(usize), .{ | 1511 | const eh_frame_ptr = math.cast(usize, try readEhPointer(&fbr, eh_frame_ptr_enc, @sizeOf(usize), .{ |
| 1581 | .pc_rel_base = @intFromPtr(&eh_frame_hdr[stream.pos]), | 1512 | .pc_rel_base = @intFromPtr(&eh_frame_hdr[fbr.pos]), |
| 1582 | .follow_indirect = true, | 1513 | .follow_indirect = true, |
| 1583 | }, builtin.cpu.arch.endian()) orelse return badDwarf()) orelse return badDwarf(); | 1514 | }) orelse return badDwarf()) orelse return badDwarf(); |
| 1584 | | 1515 | |
| 1585 | const fde_count = std.math.cast(usize, try readEhPointer(reader, fde_count_enc, @sizeOf(usize), .{ | 1516 | const fde_count = math.cast(usize, try readEhPointer(&fbr, fde_count_enc, @sizeOf(usize), .{ |
| 1586 | .pc_rel_base = @intFromPtr(&eh_frame_hdr[stream.pos]), | 1517 | .pc_rel_base = @intFromPtr(&eh_frame_hdr[fbr.pos]), |
| 1587 | .follow_indirect = true, | 1518 | .follow_indirect = true, |
| 1588 | }, builtin.cpu.arch.endian()) orelse return badDwarf()) orelse return badDwarf(); | 1519 | }) orelse return badDwarf()) orelse return badDwarf(); |
| 1589 | | 1520 | |
| 1590 | const entry_size = try ExceptionFrameHeader.entrySize(table_enc); | 1521 | const entry_size = try ExceptionFrameHeader.entrySize(table_enc); |
| 1591 | const entries_len = fde_count * entry_size; | 1522 | const entries_len = fde_count * entry_size; |
| 1592 | if (entries_len > eh_frame_hdr.len - stream.pos) return badDwarf(); | 1523 | if (entries_len > eh_frame_hdr.len - fbr.pos) return badDwarf(); |
| 1593 | | 1524 | |
| 1594 | di.eh_frame_hdr = .{ | 1525 | di.eh_frame_hdr = .{ |
| 1595 | .eh_frame_ptr = eh_frame_ptr, | 1526 | .eh_frame_ptr = eh_frame_ptr, |
| 1596 | .table_enc = table_enc, | 1527 | .table_enc = table_enc, |
| 1597 | .fde_count = fde_count, | 1528 | .fde_count = fde_count, |
| 1598 | .entries = eh_frame_hdr[stream.pos..][0..entries_len], | 1529 | .entries = eh_frame_hdr[fbr.pos..][0..entries_len], |
| 1599 | }; | 1530 | }; |
| 1600 | | 1531 | |
| 1601 | // No need to scan .eh_frame, we have a binary search table already | 1532 | // No need to scan .eh_frame, we have a binary search table already |
| ... | @@ -1605,16 +1536,16 @@ pub const DwarfInfo = struct { | ... | @@ -1605,16 +1536,16 @@ pub const DwarfInfo = struct { |
| 1605 | const frame_sections = [2]DwarfSection{ .eh_frame, .debug_frame }; | 1536 | const frame_sections = [2]DwarfSection{ .eh_frame, .debug_frame }; |
| 1606 | for (frame_sections) |frame_section| { | 1537 | for (frame_sections) |frame_section| { |
| 1607 | if (di.section(frame_section)) |section_data| { | 1538 | if (di.section(frame_section)) |section_data| { |
| 1608 | var stream = io.fixedBufferStream(section_data); | 1539 | var fbr: FixedBufferReader = .{ .buf = section_data, .endian = di.endian }; |
| 1609 | while (stream.pos < stream.buffer.len) { | 1540 | while (fbr.pos < fbr.buf.len) { |
| 1610 | const entry_header = try EntryHeader.read(&stream, frame_section, di.endian); | 1541 | const entry_header = try EntryHeader.read(&fbr, frame_section); |
| 1611 | switch (entry_header.type) { | 1542 | switch (entry_header.type) { |
| 1612 | .cie => { | 1543 | .cie => { |
| 1613 | const cie = try CommonInformationEntry.parse( | 1544 | const cie = try CommonInformationEntry.parse( |
| 1614 | entry_header.entry_bytes, | 1545 | entry_header.entry_bytes, |
| 1615 | di.sectionVirtualOffset(frame_section, base_address).?, | 1546 | di.sectionVirtualOffset(frame_section, base_address).?, |
| 1616 | true, | 1547 | true, |
| 1617 | entry_header.is_64, | 1548 | entry_header.format, |
| 1618 | frame_section, | 1549 | frame_section, |
| 1619 | entry_header.length_offset, | 1550 | entry_header.length_offset, |
| 1620 | @sizeOf(usize), | 1551 | @sizeOf(usize), |
| ... | @@ -1638,7 +1569,7 @@ pub const DwarfInfo = struct { | ... | @@ -1638,7 +1569,7 @@ pub const DwarfInfo = struct { |
| 1638 | } | 1569 | } |
| 1639 | } | 1570 | } |
| 1640 | | 1571 | |
| 1641 | std.mem.sortUnstable(FrameDescriptionEntry, di.fde_list.items, {}, struct { | 1572 | mem.sortUnstable(FrameDescriptionEntry, di.fde_list.items, {}, struct { |
| 1642 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { | 1573 | fn lessThan(ctx: void, a: FrameDescriptionEntry, b: FrameDescriptionEntry) bool { |
| 1643 | _ = ctx; | 1574 | _ = ctx; |
| 1644 | return a.pc_begin < b.pc_begin; | 1575 | return a.pc_begin < b.pc_begin; |
| ... | @@ -1668,27 +1599,31 @@ pub const DwarfInfo = struct { | ... | @@ -1668,27 +1599,31 @@ pub const DwarfInfo = struct { |
| 1668 | const frame_section = di.section(dwarf_section) orelse return error.MissingFDE; | 1599 | const frame_section = di.section(dwarf_section) orelse return error.MissingFDE; |
| 1669 | if (fde_offset >= frame_section.len) return error.MissingFDE; | 1600 | if (fde_offset >= frame_section.len) return error.MissingFDE; |
| 1670 | | 1601 | |
| 1671 | var stream = io.fixedBufferStream(frame_section); | 1602 | var fbr: FixedBufferReader = .{ |
| 1672 | try stream.seekTo(fde_offset); | 1603 | .buf = frame_section, |
| | 1604 | .pos = fde_offset, |
| | 1605 | .endian = di.endian, |
| | 1606 | }; |
| 1673 | | 1607 | |
| 1674 | const fde_entry_header = try EntryHeader.read(&stream, dwarf_section, di.endian); | 1608 | const fde_entry_header = try EntryHeader.read(&fbr, dwarf_section); |
| 1675 | if (fde_entry_header.type != .fde) return error.MissingFDE; | 1609 | if (fde_entry_header.type != .fde) return error.MissingFDE; |
| 1676 | | 1610 | |
| 1677 | const cie_offset = fde_entry_header.type.fde; | 1611 | const cie_offset = fde_entry_header.type.fde; |
| 1678 | try stream.seekTo(cie_offset); | 1612 | try fbr.seekTo(cie_offset); |
| 1679 | | 1613 | |
| 1680 | const cie_entry_header = try EntryHeader.read(&stream, dwarf_section, builtin.cpu.arch.endian()); | 1614 | fbr.endian = native_endian; |
| | 1615 | const cie_entry_header = try EntryHeader.read(&fbr, dwarf_section); |
| 1681 | if (cie_entry_header.type != .cie) return badDwarf(); | 1616 | if (cie_entry_header.type != .cie) return badDwarf(); |
| 1682 | | 1617 | |
| 1683 | cie = try CommonInformationEntry.parse( | 1618 | cie = try CommonInformationEntry.parse( |
| 1684 | cie_entry_header.entry_bytes, | 1619 | cie_entry_header.entry_bytes, |
| 1685 | 0, | 1620 | 0, |
| 1686 | true, | 1621 | true, |
| 1687 | cie_entry_header.is_64, | 1622 | cie_entry_header.format, |
| 1688 | dwarf_section, | 1623 | dwarf_section, |
| 1689 | cie_entry_header.length_offset, | 1624 | cie_entry_header.length_offset, |
| 1690 | @sizeOf(usize), | 1625 | @sizeOf(usize), |
| 1691 | builtin.cpu.arch.endian(), | 1626 | native_endian, |
| 1692 | ); | 1627 | ); |
| 1693 | | 1628 | |
| 1694 | fde = try FrameDescriptionEntry.parse( | 1629 | fde = try FrameDescriptionEntry.parse( |
| ... | @@ -1697,7 +1632,7 @@ pub const DwarfInfo = struct { | ... | @@ -1697,7 +1632,7 @@ pub const DwarfInfo = struct { |
| 1697 | true, | 1632 | true, |
| 1698 | cie, | 1633 | cie, |
| 1699 | @sizeOf(usize), | 1634 | @sizeOf(usize), |
| 1700 | builtin.cpu.arch.endian(), | 1635 | native_endian, |
| 1701 | ); | 1636 | ); |
| 1702 | } else if (di.eh_frame_hdr) |header| { | 1637 | } else if (di.eh_frame_hdr) |header| { |
| 1703 | const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null; | 1638 | const eh_frame_len = if (di.section(.eh_frame)) |eh_frame| eh_frame.len else null; |
| ... | @@ -1711,7 +1646,7 @@ pub const DwarfInfo = struct { | ... | @@ -1711,7 +1646,7 @@ pub const DwarfInfo = struct { |
| 1711 | ); | 1646 | ); |
| 1712 | } else { | 1647 | } else { |
| 1713 | const index = std.sort.binarySearch(FrameDescriptionEntry, context.pc, di.fde_list.items, {}, struct { | 1648 | const index = std.sort.binarySearch(FrameDescriptionEntry, context.pc, di.fde_list.items, {}, struct { |
| 1714 | pub fn compareFn(_: void, pc: usize, mid_item: FrameDescriptionEntry) std.math.Order { | 1649 | pub fn compareFn(_: void, pc: usize, mid_item: FrameDescriptionEntry) math.Order { |
| 1715 | if (pc < mid_item.pc_begin) return .lt; | 1650 | if (pc < mid_item.pc_begin) return .lt; |
| 1716 | | 1651 | |
| 1717 | const range_end = mid_item.pc_begin + mid_item.pc_range; | 1652 | const range_end = mid_item.pc_begin + mid_item.pc_range; |
| ... | @@ -1725,8 +1660,8 @@ pub const DwarfInfo = struct { | ... | @@ -1725,8 +1660,8 @@ pub const DwarfInfo = struct { |
| 1725 | cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE; | 1660 | cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE; |
| 1726 | } | 1661 | } |
| 1727 | | 1662 | |
| 1728 | var expression_context = .{ | 1663 | var expression_context: expressions.ExpressionContext = .{ |
| 1729 | .is_64 = cie.is_64, | 1664 | .format = cie.format, |
| 1730 | .isValidMemory = context.isValidMemory, | 1665 | .isValidMemory = context.isValidMemory, |
| 1731 | .compile_unit = di.findCompileUnit(fde.pc_begin) catch null, | 1666 | .compile_unit = di.findCompileUnit(fde.pc_begin) catch null, |
| 1732 | .thread_context = context.thread_context, | 1667 | .thread_context = context.thread_context, |
| ... | @@ -1973,10 +1908,10 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra | ... | @@ -1973,10 +1908,10 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra |
| 1973 | .raw_encoding = common_encodings[entry.encodingIndex], | 1908 | .raw_encoding = common_encodings[entry.encodingIndex], |
| 1974 | }; | 1909 | }; |
| 1975 | } else { | 1910 | } else { |
| 1976 | const local_index = try std.math.sub( | 1911 | const local_index = try math.sub( |
| 1977 | u8, | 1912 | u8, |
| 1978 | entry.encodingIndex, | 1913 | entry.encodingIndex, |
| 1979 | std.math.cast(u8, header.commonEncodingsArrayCount) orelse return error.InvalidUnwindInfo, | 1914 | math.cast(u8, header.commonEncodingsArrayCount) orelse return error.InvalidUnwindInfo, |
| 1980 | ); | 1915 | ); |
| 1981 | const local_encodings = mem.bytesAsSlice( | 1916 | const local_encodings = mem.bytesAsSlice( |
| 1982 | macho.compact_unwind_encoding_t, | 1917 | macho.compact_unwind_encoding_t, |
| ... | @@ -2187,7 +2122,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra | ... | @@ -2187,7 +2122,7 @@ pub fn unwindFrameMachO(context: *UnwindContext, unwind_info: []const u8, eh_fra |
| 2187 | | 2122 | |
| 2188 | fn unwindFrameMachODwarf(context: *UnwindContext, eh_frame: []const u8, fde_offset: usize) !usize { | 2123 | fn unwindFrameMachODwarf(context: *UnwindContext, eh_frame: []const u8, fde_offset: usize) !usize { |
| 2189 | var di = DwarfInfo{ | 2124 | var di = DwarfInfo{ |
| 2190 | .endian = builtin.cpu.arch.endian(), | 2125 | .endian = native_endian, |
| 2191 | .is_macho = true, | 2126 | .is_macho = true, |
| 2192 | }; | 2127 | }; |
| 2193 | defer di.deinit(context.allocator); | 2128 | defer di.deinit(context.allocator); |
| ... | @@ -2207,8 +2142,8 @@ pub const UnwindContext = struct { | ... | @@ -2207,8 +2142,8 @@ pub const UnwindContext = struct { |
| 2207 | thread_context: *debug.ThreadContext, | 2142 | thread_context: *debug.ThreadContext, |
| 2208 | reg_context: abi.RegisterContext, | 2143 | reg_context: abi.RegisterContext, |
| 2209 | isValidMemory: *const fn (address: usize) bool, | 2144 | isValidMemory: *const fn (address: usize) bool, |
| 2210 | vm: call_frame.VirtualMachine = .{}, | 2145 | vm: call_frame.VirtualMachine, |
| 2211 | stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{}, | 2146 | stack_machine: expressions.StackMachine(.{ .call_frame_context = true }), |
| 2212 | | 2147 | |
| 2213 | pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext { | 2148 | pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext { |
| 2214 | const pc = abi.stripInstructionPtrAuthCode((try abi.regValueNative(usize, thread_context, abi.ipRegNum(), null)).*); | 2149 | const pc = abi.stripInstructionPtrAuthCode((try abi.regValueNative(usize, thread_context, abi.ipRegNum(), null)).*); |
| ... | @@ -2223,6 +2158,8 @@ pub const UnwindContext = struct { | ... | @@ -2223,6 +2158,8 @@ pub const UnwindContext = struct { |
| 2223 | .thread_context = context_copy, | 2158 | .thread_context = context_copy, |
| 2224 | .reg_context = undefined, | 2159 | .reg_context = undefined, |
| 2225 | .isValidMemory = isValidMemory, | 2160 | .isValidMemory = isValidMemory, |
| | 2161 | .vm = .{}, |
| | 2162 | .stack_machine = .{}, |
| 2226 | }; | 2163 | }; |
| 2227 | } | 2164 | } |
| 2228 | | 2165 | |
| ... | @@ -2230,6 +2167,7 @@ pub const UnwindContext = struct { | ... | @@ -2230,6 +2167,7 @@ pub const UnwindContext = struct { |
| 2230 | self.vm.deinit(self.allocator); | 2167 | self.vm.deinit(self.allocator); |
| 2231 | self.stack_machine.deinit(self.allocator); | 2168 | self.stack_machine.deinit(self.allocator); |
| 2232 | self.allocator.destroy(self.thread_context); | 2169 | self.allocator.destroy(self.thread_context); |
| | 2170 | self.* = undefined; |
| 2233 | } | 2171 | } |
| 2234 | | 2172 | |
| 2235 | pub fn getFp(self: *const UnwindContext) !usize { | 2173 | pub fn getFp(self: *const UnwindContext) !usize { |
| ... | @@ -2281,8 +2219,7 @@ const EhPointerContext = struct { | ... | @@ -2281,8 +2219,7 @@ const EhPointerContext = struct { |
| 2281 | text_rel_base: ?u64 = null, | 2219 | text_rel_base: ?u64 = null, |
| 2282 | function_rel_base: ?u64 = null, | 2220 | function_rel_base: ?u64 = null, |
| 2283 | }; | 2221 | }; |
| 2284 | | 2222 | fn readEhPointer(fbr: *FixedBufferReader, enc: u8, addr_size_bytes: u8, ctx: EhPointerContext) !?u64 { |
| 2285 | fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerContext, endian: std.builtin.Endian) !?u64 { | | |
| 2286 | if (enc == EH.PE.omit) return null; | 2223 | if (enc == EH.PE.omit) return null; |
| 2287 | | 2224 | |
| 2288 | const value: union(enum) { | 2225 | const value: union(enum) { |
| ... | @@ -2291,20 +2228,20 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo | ... | @@ -2291,20 +2228,20 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo |
| 2291 | } = switch (enc & EH.PE.type_mask) { | 2228 | } = switch (enc & EH.PE.type_mask) { |
| 2292 | EH.PE.absptr => .{ | 2229 | EH.PE.absptr => .{ |
| 2293 | .unsigned = switch (addr_size_bytes) { | 2230 | .unsigned = switch (addr_size_bytes) { |
| 2294 | 2 => try reader.readInt(u16, endian), | 2231 | 2 => try fbr.readInt(u16), |
| 2295 | 4 => try reader.readInt(u32, endian), | 2232 | 4 => try fbr.readInt(u32), |
| 2296 | 8 => try reader.readInt(u64, endian), | 2233 | 8 => try fbr.readInt(u64), |
| 2297 | else => return error.InvalidAddrSize, | 2234 | else => return error.InvalidAddrSize, |
| 2298 | }, | 2235 | }, |
| 2299 | }, | 2236 | }, |
| 2300 | EH.PE.uleb128 => .{ .unsigned = try leb.readULEB128(u64, reader) }, | 2237 | EH.PE.uleb128 => .{ .unsigned = try fbr.readUleb128(u64) }, |
| 2301 | EH.PE.udata2 => .{ .unsigned = try reader.readInt(u16, endian) }, | 2238 | EH.PE.udata2 => .{ .unsigned = try fbr.readInt(u16) }, |
| 2302 | EH.PE.udata4 => .{ .unsigned = try reader.readInt(u32, endian) }, | 2239 | EH.PE.udata4 => .{ .unsigned = try fbr.readInt(u32) }, |
| 2303 | EH.PE.udata8 => .{ .unsigned = try reader.readInt(u64, endian) }, | 2240 | EH.PE.udata8 => .{ .unsigned = try fbr.readInt(u64) }, |
| 2304 | EH.PE.sleb128 => .{ .signed = try leb.readILEB128(i64, reader) }, | 2241 | EH.PE.sleb128 => .{ .signed = try fbr.readIleb128(i64) }, |
| 2305 | EH.PE.sdata2 => .{ .signed = try reader.readInt(i16, endian) }, | 2242 | EH.PE.sdata2 => .{ .signed = try fbr.readInt(i16) }, |
| 2306 | EH.PE.sdata4 => .{ .signed = try reader.readInt(i32, endian) }, | 2243 | EH.PE.sdata4 => .{ .signed = try fbr.readInt(i32) }, |
| 2307 | EH.PE.sdata8 => .{ .signed = try reader.readInt(i64, endian) }, | 2244 | EH.PE.sdata8 => .{ .signed = try fbr.readInt(i64) }, |
| 2308 | else => return badDwarf(), | 2245 | else => return badDwarf(), |
| 2309 | }; | 2246 | }; |
| 2310 | | 2247 | |
| ... | @@ -2396,18 +2333,17 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2396,18 +2333,17 @@ pub const ExceptionFrameHeader = struct { |
| 2396 | var left: usize = 0; | 2333 | var left: usize = 0; |
| 2397 | var len: usize = self.fde_count; | 2334 | var len: usize = self.fde_count; |
| 2398 | | 2335 | |
| 2399 | var stream = io.fixedBufferStream(self.entries); | 2336 | var fbr: FixedBufferReader = .{ .buf = self.entries, .endian = native_endian }; |
| 2400 | const reader = stream.reader(); | | |
| 2401 | | 2337 | |
| 2402 | while (len > 1) { | 2338 | while (len > 1) { |
| 2403 | const mid = left + len / 2; | 2339 | const mid = left + len / 2; |
| 2404 | | 2340 | |
| 2405 | try stream.seekTo(mid * entry_size); | 2341 | fbr.pos = mid * entry_size; |
| 2406 | const pc_begin = try readEhPointer(reader, self.table_enc, @sizeOf(usize), .{ | 2342 | const pc_begin = try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{ |
| 2407 | .pc_rel_base = @intFromPtr(&self.entries[stream.pos]), | 2343 | .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]), |
| 2408 | .follow_indirect = true, | 2344 | .follow_indirect = true, |
| 2409 | .data_rel_base = eh_frame_hdr_ptr, | 2345 | .data_rel_base = eh_frame_hdr_ptr, |
| 2410 | }, builtin.cpu.arch.endian()) orelse return badDwarf(); | 2346 | }) orelse return badDwarf(); |
| 2411 | | 2347 | |
| 2412 | if (pc < pc_begin) { | 2348 | if (pc < pc_begin) { |
| 2413 | len /= 2; | 2349 | len /= 2; |
| ... | @@ -2419,20 +2355,20 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2419,20 +2355,20 @@ pub const ExceptionFrameHeader = struct { |
| 2419 | } | 2355 | } |
| 2420 | | 2356 | |
| 2421 | if (len == 0) return badDwarf(); | 2357 | if (len == 0) return badDwarf(); |
| 2422 | try stream.seekTo(left * entry_size); | 2358 | fbr.pos = left * entry_size; |
| 2423 | | 2359 | |
| 2424 | // Read past the pc_begin field of the entry | 2360 | // Read past the pc_begin field of the entry |
| 2425 | _ = try readEhPointer(reader, self.table_enc, @sizeOf(usize), .{ | 2361 | _ = try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{ |
| 2426 | .pc_rel_base = @intFromPtr(&self.entries[stream.pos]), | 2362 | .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]), |
| 2427 | .follow_indirect = true, | 2363 | .follow_indirect = true, |
| 2428 | .data_rel_base = eh_frame_hdr_ptr, | 2364 | .data_rel_base = eh_frame_hdr_ptr, |
| 2429 | }, builtin.cpu.arch.endian()) orelse return badDwarf(); | 2365 | }) orelse return badDwarf(); |
| 2430 | | 2366 | |
| 2431 | const fde_ptr = math.cast(usize, try readEhPointer(reader, self.table_enc, @sizeOf(usize), .{ | 2367 | const fde_ptr = math.cast(usize, try readEhPointer(&fbr, self.table_enc, @sizeOf(usize), .{ |
| 2432 | .pc_rel_base = @intFromPtr(&self.entries[stream.pos]), | 2368 | .pc_rel_base = @intFromPtr(&self.entries[fbr.pos]), |
| 2433 | .follow_indirect = true, | 2369 | .follow_indirect = true, |
| 2434 | .data_rel_base = eh_frame_hdr_ptr, | 2370 | .data_rel_base = eh_frame_hdr_ptr, |
| 2435 | }, builtin.cpu.arch.endian()) orelse return badDwarf()) orelse return badDwarf(); | 2371 | }) orelse return badDwarf()) orelse return badDwarf(); |
| 2436 | | 2372 | |
| 2437 | // Verify the length fields of the FDE header are readable | 2373 | // Verify the length fields of the FDE header are readable |
| 2438 | if (!self.isValidPtr(fde_ptr, isValidMemory, eh_frame_len) or fde_ptr < self.eh_frame_ptr) return badDwarf(); | 2374 | if (!self.isValidPtr(fde_ptr, isValidMemory, eh_frame_len) or fde_ptr < self.eh_frame_ptr) return badDwarf(); |
| ... | @@ -2445,17 +2381,20 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2445,17 +2381,20 @@ pub const ExceptionFrameHeader = struct { |
| 2445 | const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse math.maxInt(u32)]; | 2381 | const eh_frame = @as([*]const u8, @ptrFromInt(self.eh_frame_ptr))[0 .. eh_frame_len orelse math.maxInt(u32)]; |
| 2446 | | 2382 | |
| 2447 | const fde_offset = fde_ptr - self.eh_frame_ptr; | 2383 | const fde_offset = fde_ptr - self.eh_frame_ptr; |
| 2448 | var eh_frame_stream = io.fixedBufferStream(eh_frame); | 2384 | var eh_frame_fbr: FixedBufferReader = .{ |
| 2449 | try eh_frame_stream.seekTo(fde_offset); | 2385 | .buf = eh_frame, |
| | 2386 | .pos = fde_offset, |
| | 2387 | .endian = native_endian, |
| | 2388 | }; |
| 2450 | | 2389 | |
| 2451 | const fde_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian()); | 2390 | const fde_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame); |
| 2452 | if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); | 2391 | if (!self.isValidPtr(@intFromPtr(&fde_entry_header.entry_bytes[fde_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); |
| 2453 | if (fde_entry_header.type != .fde) return badDwarf(); | 2392 | if (fde_entry_header.type != .fde) return badDwarf(); |
| 2454 | | 2393 | |
| 2455 | // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable | 2394 | // CIEs always come before FDEs (the offset is a subtraction), so we can assume this memory is readable |
| 2456 | const cie_offset = fde_entry_header.type.fde; | 2395 | const cie_offset = fde_entry_header.type.fde; |
| 2457 | try eh_frame_stream.seekTo(cie_offset); | 2396 | try eh_frame_fbr.seekTo(cie_offset); |
| 2458 | const cie_entry_header = try EntryHeader.read(&eh_frame_stream, .eh_frame, builtin.cpu.arch.endian()); | 2397 | const cie_entry_header = try EntryHeader.read(&eh_frame_fbr, .eh_frame); |
| 2459 | if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); | 2398 | if (!self.isValidPtr(@intFromPtr(&cie_entry_header.entry_bytes[cie_entry_header.entry_bytes.len - 1]), isValidMemory, eh_frame_len)) return badDwarf(); |
| 2460 | if (cie_entry_header.type != .cie) return badDwarf(); | 2399 | if (cie_entry_header.type != .cie) return badDwarf(); |
| 2461 | | 2400 | |
| ... | @@ -2463,11 +2402,11 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2463,11 +2402,11 @@ pub const ExceptionFrameHeader = struct { |
| 2463 | cie_entry_header.entry_bytes, | 2402 | cie_entry_header.entry_bytes, |
| 2464 | 0, | 2403 | 0, |
| 2465 | true, | 2404 | true, |
| 2466 | cie_entry_header.is_64, | 2405 | cie_entry_header.format, |
| 2467 | .eh_frame, | 2406 | .eh_frame, |
| 2468 | cie_entry_header.length_offset, | 2407 | cie_entry_header.length_offset, |
| 2469 | @sizeOf(usize), | 2408 | @sizeOf(usize), |
| 2470 | builtin.cpu.arch.endian(), | 2409 | native_endian, |
| 2471 | ); | 2410 | ); |
| 2472 | | 2411 | |
| 2473 | fde.* = try FrameDescriptionEntry.parse( | 2412 | fde.* = try FrameDescriptionEntry.parse( |
| ... | @@ -2476,7 +2415,7 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2476,7 +2415,7 @@ pub const ExceptionFrameHeader = struct { |
| 2476 | true, | 2415 | true, |
| 2477 | cie.*, | 2416 | cie.*, |
| 2478 | @sizeOf(usize), | 2417 | @sizeOf(usize), |
| 2479 | builtin.cpu.arch.endian(), | 2418 | native_endian, |
| 2480 | ); | 2419 | ); |
| 2481 | } | 2420 | } |
| 2482 | }; | 2421 | }; |
| ... | @@ -2484,62 +2423,60 @@ pub const ExceptionFrameHeader = struct { | ... | @@ -2484,62 +2423,60 @@ pub const ExceptionFrameHeader = struct { |
| 2484 | pub const EntryHeader = struct { | 2423 | pub const EntryHeader = struct { |
| 2485 | /// Offset of the length field in the backing buffer | 2424 | /// Offset of the length field in the backing buffer |
| 2486 | length_offset: usize, | 2425 | length_offset: usize, |
| 2487 | is_64: bool, | 2426 | format: Format, |
| 2488 | type: union(enum) { | 2427 | type: union(enum) { |
| 2489 | cie, | 2428 | cie, |
| 2490 | /// Value is the offset of the corresponding CIE | 2429 | /// Value is the offset of the corresponding CIE |
| 2491 | fde: u64, | 2430 | fde: u64, |
| 2492 | terminator: void, | 2431 | terminator, |
| 2493 | }, | 2432 | }, |
| 2494 | /// The entry's contents, not including the ID field | 2433 | /// The entry's contents, not including the ID field |
| 2495 | entry_bytes: []const u8, | 2434 | entry_bytes: []const u8, |
| 2496 | | 2435 | |
| 2497 | /// Reads a header for either an FDE or a CIE, then advances the stream to the position after the trailing structure. | 2436 | /// The length of the entry including the ID field, but not the length field itself |
| 2498 | /// `stream` must be a stream backed by either the .eh_frame or .debug_frame sections. | 2437 | pub fn entryLength(self: EntryHeader) usize { |
| 2499 | pub fn read(stream: *std.io.FixedBufferStream([]const u8), dwarf_section: DwarfSection, endian: std.builtin.Endian) !EntryHeader { | 2438 | return self.entry_bytes.len + @as(u8, if (self.is_64) 8 else 4); |
| 2500 | assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame); | 2439 | } |
| 2501 | | 2440 | |
| 2502 | const reader = stream.reader(); | 2441 | /// Reads a header for either an FDE or a CIE, then advances the fbr to the position after the trailing structure. |
| 2503 | const length_offset = stream.pos; | 2442 | /// `fbr` must be a FixedBufferReader backed by either the .eh_frame or .debug_frame sections. |
| | 2443 | pub fn read(fbr: *FixedBufferReader, dwarf_section: DwarfSection) !EntryHeader { |
| | 2444 | assert(dwarf_section == .eh_frame or dwarf_section == .debug_frame); |
| 2504 | | 2445 | |
| 2505 | var is_64: bool = undefined; | 2446 | const length_offset = fbr.pos; |
| 2506 | const length = math.cast(usize, try readUnitLength(reader, endian, &is_64)) orelse return badDwarf(); | 2447 | const unit_header = try readUnitHeader(fbr); |
| 2507 | if (length == 0) return .{ | 2448 | const unit_length = math.cast(usize, unit_header.unit_length) orelse return badDwarf(); |
| | 2449 | if (unit_length == 0) return .{ |
| 2508 | .length_offset = length_offset, | 2450 | .length_offset = length_offset, |
| 2509 | .is_64 = is_64, | 2451 | .format = unit_header.format, |
| 2510 | .type = .{ .terminator = {} }, | 2452 | .type = .terminator, |
| 2511 | .entry_bytes = &.{}, | 2453 | .entry_bytes = &.{}, |
| 2512 | }; | 2454 | }; |
| | 2455 | const start_offset = fbr.pos; |
| | 2456 | const end_offset = start_offset + unit_length; |
| | 2457 | defer fbr.pos = end_offset; |
| 2513 | | 2458 | |
| 2514 | const id_len = @as(u8, if (is_64) 8 else 4); | 2459 | const id = try fbr.readAddress(unit_header.format); |
| 2515 | const id = if (is_64) try reader.readInt(u64, endian) else try reader.readInt(u32, endian); | 2460 | const entry_bytes = fbr.buf[fbr.pos..end_offset]; |
| 2516 | const entry_bytes = stream.buffer[stream.pos..][0 .. length - id_len]; | | |
| 2517 | const cie_id: u64 = switch (dwarf_section) { | 2461 | const cie_id: u64 = switch (dwarf_section) { |
| 2518 | .eh_frame => CommonInformationEntry.eh_id, | 2462 | .eh_frame => CommonInformationEntry.eh_id, |
| 2519 | .debug_frame => if (is_64) CommonInformationEntry.dwarf64_id else CommonInformationEntry.dwarf32_id, | 2463 | .debug_frame => switch (unit_header.format) { |
| | 2464 | .@"32" => CommonInformationEntry.dwarf32_id, |
| | 2465 | .@"64" => CommonInformationEntry.dwarf64_id, |
| | 2466 | }, |
| 2520 | else => unreachable, | 2467 | else => unreachable, |
| 2521 | }; | 2468 | }; |
| 2522 | | 2469 | |
| 2523 | const result = EntryHeader{ | 2470 | return .{ |
| 2524 | .length_offset = length_offset, | 2471 | .length_offset = length_offset, |
| 2525 | .is_64 = is_64, | 2472 | .format = unit_header.format, |
| 2526 | .type = if (id == cie_id) .{ .cie = {} } else .{ | 2473 | .type = if (id == cie_id) .cie else .{ .fde = switch (dwarf_section) { |
| 2527 | .fde = switch (dwarf_section) { | 2474 | .eh_frame => try math.sub(u64, start_offset, id), |
| 2528 | .eh_frame => try std.math.sub(u64, stream.pos - id_len, id), | 2475 | .debug_frame => id, |
| 2529 | .debug_frame => id, | 2476 | else => unreachable, |
| 2530 | else => unreachable, | 2477 | } }, |
| 2531 | }, | | |
| 2532 | }, | | |
| 2533 | .entry_bytes = entry_bytes, | 2478 | .entry_bytes = entry_bytes, |
| 2534 | }; | 2479 | }; |
| 2535 | | | |
| 2536 | stream.pos += entry_bytes.len; | | |
| 2537 | return result; | | |
| 2538 | } | | |
| 2539 | | | |
| 2540 | /// The length of the entry including the ID field, but not the length field itself | | |
| 2541 | pub fn entryLength(self: EntryHeader) usize { | | |
| 2542 | return self.entry_bytes.len + @as(u8, if (self.is_64) 8 else 4); | | |
| 2543 | } | 2480 | } |
| 2544 | }; | 2481 | }; |
| 2545 | | 2482 | |
| ... | @@ -2558,7 +2495,7 @@ pub const CommonInformationEntry = struct { | ... | @@ -2558,7 +2495,7 @@ pub const CommonInformationEntry = struct { |
| 2558 | length_offset: u64, | 2495 | length_offset: u64, |
| 2559 | version: u8, | 2496 | version: u8, |
| 2560 | address_size: u8, | 2497 | address_size: u8, |
| 2561 | is_64: bool, | 2498 | format: Format, |
| 2562 | | 2499 | |
| 2563 | // Only present in version 4 | 2500 | // Only present in version 4 |
| 2564 | segment_selector_size: ?u8, | 2501 | segment_selector_size: ?u8, |
| ... | @@ -2602,7 +2539,7 @@ pub const CommonInformationEntry = struct { | ... | @@ -2602,7 +2539,7 @@ pub const CommonInformationEntry = struct { |
| 2602 | cie_bytes: []const u8, | 2539 | cie_bytes: []const u8, |
| 2603 | pc_rel_offset: i64, | 2540 | pc_rel_offset: i64, |
| 2604 | is_runtime: bool, | 2541 | is_runtime: bool, |
| 2605 | is_64: bool, | 2542 | format: Format, |
| 2606 | dwarf_section: DwarfSection, | 2543 | dwarf_section: DwarfSection, |
| 2607 | length_offset: u64, | 2544 | length_offset: u64, |
| 2608 | addr_size_bytes: u8, | 2545 | addr_size_bytes: u8, |
| ... | @@ -2610,10 +2547,9 @@ pub const CommonInformationEntry = struct { | ... | @@ -2610,10 +2547,9 @@ pub const CommonInformationEntry = struct { |
| 2610 | ) !CommonInformationEntry { | 2547 | ) !CommonInformationEntry { |
| 2611 | if (addr_size_bytes > 8) return error.UnsupportedAddrSize; | 2548 | if (addr_size_bytes > 8) return error.UnsupportedAddrSize; |
| 2612 | | 2549 | |
| 2613 | var stream = io.fixedBufferStream(cie_bytes); | 2550 | var fbr: FixedBufferReader = .{ .buf = cie_bytes, .endian = endian }; |
| 2614 | const reader = stream.reader(); | | |
| 2615 | | 2551 | |
| 2616 | const version = try reader.readByte(); | 2552 | const version = try fbr.readByte(); |
| 2617 | switch (dwarf_section) { | 2553 | switch (dwarf_section) { |
| 2618 | .eh_frame => if (version != 1 and version != 3) return error.UnsupportedDwarfVersion, | 2554 | .eh_frame => if (version != 1 and version != 3) return error.UnsupportedDwarfVersion, |
| 2619 | .debug_frame => if (version != 4) return error.UnsupportedDwarfVersion, | 2555 | .debug_frame => if (version != 4) return error.UnsupportedDwarfVersion, |
| ... | @@ -2624,9 +2560,9 @@ pub const CommonInformationEntry = struct { | ... | @@ -2624,9 +2560,9 @@ pub const CommonInformationEntry = struct { |
| 2624 | var has_aug_data = false; | 2560 | var has_aug_data = false; |
| 2625 | | 2561 | |
| 2626 | var aug_str_len: usize = 0; | 2562 | var aug_str_len: usize = 0; |
| 2627 | const aug_str_start = stream.pos; | 2563 | const aug_str_start = fbr.pos; |
| 2628 | var aug_byte = try reader.readByte(); | 2564 | var aug_byte = try fbr.readByte(); |
| 2629 | while (aug_byte != 0) : (aug_byte = try reader.readByte()) { | 2565 | while (aug_byte != 0) : (aug_byte = try fbr.readByte()) { |
| 2630 | switch (aug_byte) { | 2566 | switch (aug_byte) { |
| 2631 | 'z' => { | 2567 | 'z' => { |
| 2632 | if (aug_str_len != 0) return badDwarf(); | 2568 | if (aug_str_len != 0) return badDwarf(); |
| ... | @@ -2634,7 +2570,7 @@ pub const CommonInformationEntry = struct { | ... | @@ -2634,7 +2570,7 @@ pub const CommonInformationEntry = struct { |
| 2634 | }, | 2570 | }, |
| 2635 | 'e' => { | 2571 | 'e' => { |
| 2636 | if (has_aug_data or aug_str_len != 0) return badDwarf(); | 2572 | if (has_aug_data or aug_str_len != 0) return badDwarf(); |
| 2637 | if (try reader.readByte() != 'h') return badDwarf(); | 2573 | if (try fbr.readByte() != 'h') return badDwarf(); |
| 2638 | has_eh_data = true; | 2574 | has_eh_data = true; |
| 2639 | }, | 2575 | }, |
| 2640 | else => if (has_eh_data) return badDwarf(), | 2576 | else => if (has_eh_data) return badDwarf(), |
| ... | @@ -2645,15 +2581,15 @@ pub const CommonInformationEntry = struct { | ... | @@ -2645,15 +2581,15 @@ pub const CommonInformationEntry = struct { |
| 2645 | | 2581 | |
| 2646 | if (has_eh_data) { | 2582 | if (has_eh_data) { |
| 2647 | // legacy data created by older versions of gcc - unsupported here | 2583 | // legacy data created by older versions of gcc - unsupported here |
| 2648 | for (0..addr_size_bytes) |_| _ = try reader.readByte(); | 2584 | for (0..addr_size_bytes) |_| _ = try fbr.readByte(); |
| 2649 | } | 2585 | } |
| 2650 | | 2586 | |
| 2651 | const address_size = if (version == 4) try reader.readByte() else addr_size_bytes; | 2587 | const address_size = if (version == 4) try fbr.readByte() else addr_size_bytes; |
| 2652 | const segment_selector_size = if (version == 4) try reader.readByte() else null; | 2588 | const segment_selector_size = if (version == 4) try fbr.readByte() else null; |
| 2653 | | 2589 | |
| 2654 | const code_alignment_factor = try leb.readULEB128(u32, reader); | 2590 | const code_alignment_factor = try fbr.readUleb128(u32); |
| 2655 | const data_alignment_factor = try leb.readILEB128(i32, reader); | 2591 | const data_alignment_factor = try fbr.readIleb128(i32); |
| 2656 | const return_address_register = if (version == 1) try reader.readByte() else try leb.readULEB128(u8, reader); | 2592 | const return_address_register = if (version == 1) try fbr.readByte() else try fbr.readUleb128(u8); |
| 2657 | | 2593 | |
| 2658 | var lsda_pointer_enc: u8 = EH.PE.omit; | 2594 | var lsda_pointer_enc: u8 = EH.PE.omit; |
| 2659 | var personality_enc: ?u8 = null; | 2595 | var personality_enc: ?u8 = null; |
| ... | @@ -2662,31 +2598,25 @@ pub const CommonInformationEntry = struct { | ... | @@ -2662,31 +2598,25 @@ pub const CommonInformationEntry = struct { |
| 2662 | | 2598 | |
| 2663 | var aug_data: []const u8 = &[_]u8{}; | 2599 | var aug_data: []const u8 = &[_]u8{}; |
| 2664 | const aug_str = if (has_aug_data) blk: { | 2600 | const aug_str = if (has_aug_data) blk: { |
| 2665 | const aug_data_len = try leb.readULEB128(usize, reader); | 2601 | const aug_data_len = try fbr.readUleb128(usize); |
| 2666 | const aug_data_start = stream.pos; | 2602 | const aug_data_start = fbr.pos; |
| 2667 | aug_data = cie_bytes[aug_data_start..][0..aug_data_len]; | 2603 | aug_data = cie_bytes[aug_data_start..][0..aug_data_len]; |
| 2668 | | 2604 | |
| 2669 | const aug_str = cie_bytes[aug_str_start..][0..aug_str_len]; | 2605 | const aug_str = cie_bytes[aug_str_start..][0..aug_str_len]; |
| 2670 | for (aug_str[1..]) |byte| { | 2606 | for (aug_str[1..]) |byte| { |
| 2671 | switch (byte) { | 2607 | switch (byte) { |
| 2672 | 'L' => { | 2608 | 'L' => { |
| 2673 | lsda_pointer_enc = try reader.readByte(); | 2609 | lsda_pointer_enc = try fbr.readByte(); |
| 2674 | }, | 2610 | }, |
| 2675 | 'P' => { | 2611 | 'P' => { |
| 2676 | personality_enc = try reader.readByte(); | 2612 | personality_enc = try fbr.readByte(); |
| 2677 | personality_routine_pointer = try readEhPointer( | 2613 | personality_routine_pointer = try readEhPointer(&fbr, personality_enc.?, addr_size_bytes, .{ |
| 2678 | reader, | 2614 | .pc_rel_base = try pcRelBase(@intFromPtr(&cie_bytes[fbr.pos]), pc_rel_offset), |
| 2679 | personality_enc.?, | 2615 | .follow_indirect = is_runtime, |
| 2680 | addr_size_bytes, | 2616 | }); |
| 2681 | .{ | | |
| 2682 | .pc_rel_base = try pcRelBase(@intFromPtr(&cie_bytes[stream.pos]), pc_rel_offset), | | |
| 2683 | .follow_indirect = is_runtime, | | |
| 2684 | }, | | |
| 2685 | endian, | | |
| 2686 | ); | | |
| 2687 | }, | 2617 | }, |
| 2688 | 'R' => { | 2618 | 'R' => { |
| 2689 | fde_pointer_enc = try reader.readByte(); | 2619 | fde_pointer_enc = try fbr.readByte(); |
| 2690 | }, | 2620 | }, |
| 2691 | 'S', 'B', 'G' => {}, | 2621 | 'S', 'B', 'G' => {}, |
| 2692 | else => return badDwarf(), | 2622 | else => return badDwarf(), |
| ... | @@ -2694,16 +2624,16 @@ pub const CommonInformationEntry = struct { | ... | @@ -2694,16 +2624,16 @@ pub const CommonInformationEntry = struct { |
| 2694 | } | 2624 | } |
| 2695 | | 2625 | |
| 2696 | // aug_data_len can include padding so the CIE ends on an address boundary | 2626 | // aug_data_len can include padding so the CIE ends on an address boundary |
| 2697 | try stream.seekTo(aug_data_start + aug_data_len); | 2627 | fbr.pos = aug_data_start + aug_data_len; |
| 2698 | break :blk aug_str; | 2628 | break :blk aug_str; |
| 2699 | } else &[_]u8{}; | 2629 | } else &[_]u8{}; |
| 2700 | | 2630 | |
| 2701 | const initial_instructions = cie_bytes[stream.pos..]; | 2631 | const initial_instructions = cie_bytes[fbr.pos..]; |
| 2702 | return .{ | 2632 | return .{ |
| 2703 | .length_offset = length_offset, | 2633 | .length_offset = length_offset, |
| 2704 | .version = version, | 2634 | .version = version, |
| 2705 | .address_size = address_size, | 2635 | .address_size = address_size, |
| 2706 | .is_64 = is_64, | 2636 | .format = format, |
| 2707 | .segment_selector_size = segment_selector_size, | 2637 | .segment_selector_size = segment_selector_size, |
| 2708 | .code_alignment_factor = code_alignment_factor, | 2638 | .code_alignment_factor = code_alignment_factor, |
| 2709 | .data_alignment_factor = data_alignment_factor, | 2639 | .data_alignment_factor = data_alignment_factor, |
| ... | @@ -2751,56 +2681,37 @@ pub const FrameDescriptionEntry = struct { | ... | @@ -2751,56 +2681,37 @@ pub const FrameDescriptionEntry = struct { |
| 2751 | ) !FrameDescriptionEntry { | 2681 | ) !FrameDescriptionEntry { |
| 2752 | if (addr_size_bytes > 8) return error.InvalidAddrSize; | 2682 | if (addr_size_bytes > 8) return error.InvalidAddrSize; |
| 2753 | | 2683 | |
| 2754 | var stream = io.fixedBufferStream(fde_bytes); | 2684 | var fbr: FixedBufferReader = .{ .buf = fde_bytes, .endian = endian }; |
| 2755 | const reader = stream.reader(); | | |
| 2756 | | 2685 | |
| 2757 | const pc_begin = try readEhPointer( | 2686 | const pc_begin = try readEhPointer(&fbr, cie.fde_pointer_enc, addr_size_bytes, .{ |
| 2758 | reader, | 2687 | .pc_rel_base = try pcRelBase(@intFromPtr(&fde_bytes[fbr.pos]), pc_rel_offset), |
| 2759 | cie.fde_pointer_enc, | 2688 | .follow_indirect = is_runtime, |
| 2760 | addr_size_bytes, | 2689 | }) orelse return badDwarf(); |
| 2761 | .{ | 2690 | |
| 2762 | .pc_rel_base = try pcRelBase(@intFromPtr(&fde_bytes[stream.pos]), pc_rel_offset), | 2691 | const pc_range = try readEhPointer(&fbr, cie.fde_pointer_enc, addr_size_bytes, .{ |
| 2763 | .follow_indirect = is_runtime, | 2692 | .pc_rel_base = 0, |
| 2764 | }, | 2693 | .follow_indirect = false, |
| 2765 | endian, | 2694 | }) orelse return badDwarf(); |
| 2766 | ) orelse return badDwarf(); | | |
| 2767 | | | |
| 2768 | const pc_range = try readEhPointer( | | |
| 2769 | reader, | | |
| 2770 | cie.fde_pointer_enc, | | |
| 2771 | addr_size_bytes, | | |
| 2772 | .{ | | |
| 2773 | .pc_rel_base = 0, | | |
| 2774 | .follow_indirect = false, | | |
| 2775 | }, | | |
| 2776 | endian, | | |
| 2777 | ) orelse return badDwarf(); | | |
| 2778 | | 2695 | |
| 2779 | var aug_data: []const u8 = &[_]u8{}; | 2696 | var aug_data: []const u8 = &[_]u8{}; |
| 2780 | const lsda_pointer = if (cie.aug_str.len > 0) blk: { | 2697 | const lsda_pointer = if (cie.aug_str.len > 0) blk: { |
| 2781 | const aug_data_len = try leb.readULEB128(usize, reader); | 2698 | const aug_data_len = try fbr.readUleb128(usize); |
| 2782 | const aug_data_start = stream.pos; | 2699 | const aug_data_start = fbr.pos; |
| 2783 | aug_data = fde_bytes[aug_data_start..][0..aug_data_len]; | 2700 | aug_data = fde_bytes[aug_data_start..][0..aug_data_len]; |
| 2784 | | 2701 | |
| 2785 | const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit) | 2702 | const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit) |
| 2786 | try readEhPointer( | 2703 | try readEhPointer(&fbr, cie.lsda_pointer_enc, addr_size_bytes, .{ |
| 2787 | reader, | 2704 | .pc_rel_base = try pcRelBase(@intFromPtr(&fde_bytes[fbr.pos]), pc_rel_offset), |
| 2788 | cie.lsda_pointer_enc, | 2705 | .follow_indirect = is_runtime, |
| 2789 | addr_size_bytes, | 2706 | }) |
| 2790 | .{ | | |
| 2791 | .pc_rel_base = try pcRelBase(@intFromPtr(&fde_bytes[stream.pos]), pc_rel_offset), | | |
| 2792 | .follow_indirect = is_runtime, | | |
| 2793 | }, | | |
| 2794 | endian, | | |
| 2795 | ) | | |
| 2796 | else | 2707 | else |
| 2797 | null; | 2708 | null; |
| 2798 | | 2709 | |
| 2799 | try stream.seekTo(aug_data_start + aug_data_len); | 2710 | fbr.pos = aug_data_start + aug_data_len; |
| 2800 | break :blk lsda_pointer; | 2711 | break :blk lsda_pointer; |
| 2801 | } else null; | 2712 | } else null; |
| 2802 | | 2713 | |
| 2803 | const instructions = fde_bytes[stream.pos..]; | 2714 | const instructions = fde_bytes[fbr.pos..]; |
| 2804 | return .{ | 2715 | return .{ |
| 2805 | .cie_length_offset = cie.length_offset, | 2716 | .cie_length_offset = cie.length_offset, |
| 2806 | .pc_begin = pc_begin, | 2717 | .pc_begin = pc_begin, |
| ... | @@ -2820,6 +2731,75 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize { | ... | @@ -2820,6 +2731,75 @@ fn pcRelBase(field_ptr: usize, pc_rel_offset: i64) !usize { |
| 2820 | } | 2731 | } |
| 2821 | } | 2732 | } |
| 2822 | | 2733 | |
| | 2734 | // Reading debug info needs to be fast, even when compiled in debug mode, |
| | 2735 | // so avoid using a `std.io.FixedBufferStream` which is too slow. |
| | 2736 | const FixedBufferReader = struct { |
| | 2737 | buf: []const u8, |
| | 2738 | pos: usize = 0, |
| | 2739 | endian: std.builtin.Endian, |
| | 2740 | |
| | 2741 | pub const Error = error{ EndOfBuffer, Overflow }; |
| | 2742 | |
| | 2743 | fn seekTo(fbr: *FixedBufferReader, pos: u64) Error!void { |
| | 2744 | if (pos > fbr.buf.len) return error.EndOfBuffer; |
| | 2745 | fbr.pos = @intCast(pos); |
| | 2746 | } |
| | 2747 | |
| | 2748 | fn seekForward(fbr: *FixedBufferReader, amount: u64) Error!void { |
| | 2749 | if (fbr.buf.len - fbr.pos < amount) return error.EndOfBuffer; |
| | 2750 | fbr.pos += @intCast(amount); |
| | 2751 | } |
| | 2752 | |
| | 2753 | pub inline fn readByte(fbr: *FixedBufferReader) Error!u8 { |
| | 2754 | if (fbr.pos >= fbr.buf.len) return error.EndOfBuffer; |
| | 2755 | defer fbr.pos += 1; |
| | 2756 | return fbr.buf[fbr.pos]; |
| | 2757 | } |
| | 2758 | |
| | 2759 | fn readByteSigned(fbr: *FixedBufferReader) Error!i8 { |
| | 2760 | return @bitCast(try fbr.readByte()); |
| | 2761 | } |
| | 2762 | |
| | 2763 | fn readInt(fbr: *FixedBufferReader, comptime T: type) Error!T { |
| | 2764 | const size = @divExact(@typeInfo(T).Int.bits, 8); |
| | 2765 | if (fbr.buf.len - fbr.pos < size) return error.EndOfBuffer; |
| | 2766 | defer fbr.pos += size; |
| | 2767 | return mem.readInt(T, fbr.buf[fbr.pos..][0..size], fbr.endian); |
| | 2768 | } |
| | 2769 | |
| | 2770 | fn readUleb128(fbr: *FixedBufferReader, comptime T: type) Error!T { |
| | 2771 | return std.leb.readULEB128(T, fbr); |
| | 2772 | } |
| | 2773 | |
| | 2774 | fn readIleb128(fbr: *FixedBufferReader, comptime T: type) Error!T { |
| | 2775 | return std.leb.readILEB128(T, fbr); |
| | 2776 | } |
| | 2777 | |
| | 2778 | fn readAddress(fbr: *FixedBufferReader, format: Format) Error!u64 { |
| | 2779 | return switch (format) { |
| | 2780 | .@"32" => try fbr.readInt(u32), |
| | 2781 | .@"64" => try fbr.readInt(u64), |
| | 2782 | }; |
| | 2783 | } |
| | 2784 | |
| | 2785 | fn readBytes(fbr: *FixedBufferReader, len: usize) Error![]const u8 { |
| | 2786 | if (fbr.buf.len - fbr.pos < len) return error.EndOfBuffer; |
| | 2787 | defer fbr.pos += len; |
| | 2788 | return fbr.buf[fbr.pos..][0..len]; |
| | 2789 | } |
| | 2790 | |
| | 2791 | fn readBytesTo(fbr: *FixedBufferReader, comptime sentinel: u8) Error![:sentinel]const u8 { |
| | 2792 | const end = @call(.always_inline, mem.indexOfScalarPos, .{ |
| | 2793 | u8, |
| | 2794 | fbr.buf, |
| | 2795 | fbr.pos, |
| | 2796 | sentinel, |
| | 2797 | }) orelse return error.EndOfBuffer; |
| | 2798 | defer fbr.pos = end + 1; |
| | 2799 | return fbr.buf[fbr.pos..end :sentinel]; |
| | 2800 | } |
| | 2801 | }; |
| | 2802 | |
| 2823 | test { | 2803 | test { |
| 2824 | std.testing.refAllDecls(@This()); | 2804 | std.testing.refAllDecls(@This()); |
| 2825 | } | 2805 | } |