blob 36c8a794 (25795B) - Raw
1 const std = @import("std"); 2 const assert = std.debug.assert; 3 const macho = std.macho; 4 const math = std.math; 5 const mem = std.mem; 6 const leb = std.leb; 7 const log = std.log.scoped(.eh_frame); 8 9 const Allocator = mem.Allocator; 10 const AtomIndex = @import("zld.zig").AtomIndex; 11 const Atom = @import("ZldAtom.zig"); 12 const Relocation = @import("Relocation.zig"); 13 const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; 14 const UnwindInfo = @import("UnwindInfo.zig"); 15 const Zld = @import("zld.zig").Zld; 16 17 pub fn scanRelocs(zld: *Zld) !void { 18 const gpa = zld.gpa; 19 20 for (zld.objects.items, 0..) |*object, object_id| { 21 var cies = std.AutoHashMap(u32, void).init(gpa); 22 defer cies.deinit(); 23 24 var it = object.getEhFrameRecordsIterator(); 25 26 for (object.exec_atoms.items) |atom_index| { 27 const fde_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; 28 if (object.eh_frame_relocs_lookup.get(fde_offset).?.dead) continue; 29 it.seekTo(fde_offset); 30 const fde = (try it.next()).?; 31 32 const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset); 33 const cie_offset = fde_offset + 4 - cie_ptr; 34 35 if (!cies.contains(cie_offset)) { 36 try cies.putNoClobber(cie_offset, {}); 37 it.seekTo(cie_offset); 38 const cie = (try it.next()).?; 39 try cie.scanRelocs(zld, @as(u32, @intCast(object_id)), cie_offset); 40 } 41 } 42 } 43 } 44 45 pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void { 46 const sect_id = zld.getSectionByName("__TEXT", "__eh_frame") orelse return; 47 const sect = &zld.sections.items(.header)[sect_id]; 48 sect.@"align" = 3; 49 sect.size = 0; 50 51 const cpu_arch = zld.options.target.cpu.arch; 52 const gpa = zld.gpa; 53 var size: u32 = 0; 54 55 for (zld.objects.items, 0..) |*object, object_id| { 56 var cies = std.AutoHashMap(u32, u32).init(gpa); 57 defer cies.deinit(); 58 59 var eh_it = object.getEhFrameRecordsIterator(); 60 61 for (object.exec_atoms.items) |atom_index| { 62 const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; 63 if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; 64 65 const record_id = unwind_info.records_lookup.get(atom_index) orelse continue; 66 const record = unwind_info.records.items[record_id]; 67 68 // TODO skip this check if no __compact_unwind is present 69 const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); 70 if (!is_dwarf) continue; 71 72 eh_it.seekTo(fde_record_offset); 73 const source_fde_record = (try eh_it.next()).?; 74 75 const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); 76 const cie_offset = fde_record_offset + 4 - cie_ptr; 77 78 const gop = try cies.getOrPut(cie_offset); 79 if (!gop.found_existing) { 80 eh_it.seekTo(cie_offset); 81 const source_cie_record = (try eh_it.next()).?; 82 gop.value_ptr.* = size; 83 size += source_cie_record.getSize(); 84 } 85 86 size += source_fde_record.getSize(); 87 } 88 } 89 90 sect.size = size; 91 } 92 93 pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void { 94 const sect_id = zld.getSectionByName("__TEXT", "__eh_frame") orelse return; 95 const sect = zld.sections.items(.header)[sect_id]; 96 const seg_id = zld.sections.items(.segment_index)[sect_id]; 97 const seg = zld.segments.items[seg_id]; 98 99 const cpu_arch = zld.options.target.cpu.arch; 100 const gpa = zld.gpa; 101 102 var eh_records = std.AutoArrayHashMap(u32, EhFrameRecord(true)).init(gpa); 103 defer { 104 for (eh_records.values()) |*rec| { 105 rec.deinit(gpa); 106 } 107 eh_records.deinit(); 108 } 109 110 var eh_frame_offset: u32 = 0; 111 112 for (zld.objects.items, 0..) |*object, object_id| { 113 try eh_records.ensureUnusedCapacity(2 * @as(u32, @intCast(object.exec_atoms.items.len))); 114 115 var cies = std.AutoHashMap(u32, u32).init(gpa); 116 defer cies.deinit(); 117 118 var eh_it = object.getEhFrameRecordsIterator(); 119 120 for (object.exec_atoms.items) |atom_index| { 121 const fde_record_offset = object.eh_frame_records_lookup.get(atom_index) orelse continue; 122 if (object.eh_frame_relocs_lookup.get(fde_record_offset).?.dead) continue; 123 124 const record_id = unwind_info.records_lookup.get(atom_index) orelse continue; 125 const record = &unwind_info.records.items[record_id]; 126 127 // TODO skip this check if no __compact_unwind is present 128 const is_dwarf = UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch); 129 if (!is_dwarf) continue; 130 131 eh_it.seekTo(fde_record_offset); 132 const source_fde_record = (try eh_it.next()).?; 133 134 const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset); 135 const cie_offset = fde_record_offset + 4 - cie_ptr; 136 137 const gop = try cies.getOrPut(cie_offset); 138 if (!gop.found_existing) { 139 eh_it.seekTo(cie_offset); 140 const source_cie_record = (try eh_it.next()).?; 141 var cie_record = try source_cie_record.toOwned(gpa); 142 try cie_record.relocate(zld, @as(u32, @intCast(object_id)), .{ 143 .source_offset = cie_offset, 144 .out_offset = eh_frame_offset, 145 .sect_addr = sect.addr, 146 }); 147 eh_records.putAssumeCapacityNoClobber(eh_frame_offset, cie_record); 148 gop.value_ptr.* = eh_frame_offset; 149 eh_frame_offset += cie_record.getSize(); 150 } 151 152 var fde_record = try source_fde_record.toOwned(gpa); 153 try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{ 154 .source_offset = fde_record_offset, 155 .out_offset = eh_frame_offset, 156 .sect_addr = sect.addr, 157 }); 158 fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*); 159 160 switch (cpu_arch) { 161 .aarch64 => {}, // relocs take care of LSDA pointers 162 .x86_64 => { 163 // We need to relocate target symbol address ourselves. 164 const atom = zld.getAtom(atom_index); 165 const atom_sym = zld.getSymbol(atom.getSymbolWithLoc()); 166 try fde_record.setTargetSymbolAddress(atom_sym.n_value, .{ 167 .base_addr = sect.addr, 168 .base_offset = eh_frame_offset, 169 }); 170 171 // We need to parse LSDA pointer and relocate ourselves. 172 const cie_record = eh_records.get( 173 eh_frame_offset + 4 - fde_record.getCiePointer(), 174 ).?; 175 const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?); 176 const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ 177 .base_addr = eh_frame_sect.addr, 178 .base_offset = fde_record_offset, 179 }); 180 if (source_lsda_ptr) |ptr| { 181 const sym_index = object.getSymbolByAddress(ptr, null); 182 const sym = object.symtab[sym_index]; 183 try fde_record.setLsdaPointer(cie_record, sym.n_value, .{ 184 .base_addr = sect.addr, 185 .base_offset = eh_frame_offset, 186 }); 187 } 188 }, 189 else => unreachable, 190 } 191 192 eh_records.putAssumeCapacityNoClobber(eh_frame_offset, fde_record); 193 194 UnwindInfo.UnwindEncoding.setDwarfSectionOffset( 195 &record.compactUnwindEncoding, 196 cpu_arch, 197 @as(u24, @intCast(eh_frame_offset)), 198 ); 199 200 const cie_record = eh_records.get( 201 eh_frame_offset + 4 - fde_record.getCiePointer(), 202 ).?; 203 const lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{ 204 .base_addr = sect.addr, 205 .base_offset = eh_frame_offset, 206 }); 207 if (lsda_ptr) |ptr| { 208 record.lsda = ptr - seg.vmaddr; 209 } 210 211 eh_frame_offset += fde_record.getSize(); 212 } 213 } 214 215 var buffer = std.ArrayList(u8).init(gpa); 216 defer buffer.deinit(); 217 const writer = buffer.writer(); 218 219 for (eh_records.values()) |record| { 220 try writer.writeIntLittle(u32, record.size); 221 try buffer.appendSlice(record.data); 222 } 223 224 try zld.file.pwriteAll(buffer.items, sect.offset); 225 } 226 const EhFrameRecordTag = enum { cie, fde }; 227 228 pub fn EhFrameRecord(comptime is_mutable: bool) type { 229 return struct { 230 tag: EhFrameRecordTag, 231 size: u32, 232 data: if (is_mutable) []u8 else []const u8, 233 234 const Record = @This(); 235 236 pub fn deinit(rec: *Record, gpa: Allocator) void { 237 comptime assert(is_mutable); 238 gpa.free(rec.data); 239 } 240 241 pub fn toOwned(rec: Record, gpa: Allocator) Allocator.Error!EhFrameRecord(true) { 242 const data = try gpa.dupe(u8, rec.data); 243 return EhFrameRecord(true){ 244 .tag = rec.tag, 245 .size = rec.size, 246 .data = data, 247 }; 248 } 249 250 pub inline fn getSize(rec: Record) u32 { 251 return 4 + rec.size; 252 } 253 254 pub fn scanRelocs( 255 rec: Record, 256 zld: *Zld, 257 object_id: u32, 258 source_offset: u32, 259 ) !void { 260 if (rec.getPersonalityPointerReloc(zld, object_id, source_offset)) |target| { 261 try Atom.addGotEntry(zld, target); 262 } 263 } 264 265 pub fn getTargetSymbolAddress(rec: Record, ctx: struct { 266 base_addr: u64, 267 base_offset: u64, 268 }) u64 { 269 assert(rec.tag == .fde); 270 const addend = mem.readIntLittle(i64, rec.data[4..][0..8]); 271 return @as(u64, @intCast(@as(i64, @intCast(ctx.base_addr + ctx.base_offset + 8)) + addend)); 272 } 273 274 pub fn setTargetSymbolAddress(rec: *Record, value: u64, ctx: struct { 275 base_addr: u64, 276 base_offset: u64, 277 }) !void { 278 assert(rec.tag == .fde); 279 const addend = @as(i64, @intCast(value)) - @as(i64, @intCast(ctx.base_addr + ctx.base_offset + 8)); 280 mem.writeIntLittle(i64, rec.data[4..][0..8], addend); 281 } 282 283 pub fn getPersonalityPointerReloc( 284 rec: Record, 285 zld: *Zld, 286 object_id: u32, 287 source_offset: u32, 288 ) ?SymbolWithLoc { 289 const cpu_arch = zld.options.target.cpu.arch; 290 const relocs = getRelocs(zld, object_id, source_offset); 291 for (relocs) |rel| { 292 switch (cpu_arch) { 293 .aarch64 => { 294 const rel_type = @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)); 295 switch (rel_type) { 296 .ARM64_RELOC_SUBTRACTOR, 297 .ARM64_RELOC_UNSIGNED, 298 => continue, 299 .ARM64_RELOC_POINTER_TO_GOT => {}, 300 else => unreachable, 301 } 302 }, 303 .x86_64 => { 304 const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type)); 305 switch (rel_type) { 306 .X86_64_RELOC_GOT => {}, 307 else => unreachable, 308 } 309 }, 310 else => unreachable, 311 } 312 const target = Atom.parseRelocTarget(zld, .{ 313 .object_id = object_id, 314 .rel = rel, 315 .code = rec.data, 316 .base_offset = @as(i32, @intCast(source_offset)) + 4, 317 }); 318 return target; 319 } 320 return null; 321 } 322 323 pub fn relocate(rec: *Record, zld: *Zld, object_id: u32, ctx: struct { 324 source_offset: u32, 325 out_offset: u32, 326 sect_addr: u64, 327 }) !void { 328 comptime assert(is_mutable); 329 330 const cpu_arch = zld.options.target.cpu.arch; 331 const relocs = getRelocs(zld, object_id, ctx.source_offset); 332 333 for (relocs) |rel| { 334 const target = Atom.parseRelocTarget(zld, .{ 335 .object_id = object_id, 336 .rel = rel, 337 .code = rec.data, 338 .base_offset = @as(i32, @intCast(ctx.source_offset)) + 4, 339 }); 340 const rel_offset = @as(u32, @intCast(rel.r_address - @as(i32, @intCast(ctx.source_offset)) - 4)); 341 const source_addr = ctx.sect_addr + rel_offset + ctx.out_offset + 4; 342 343 switch (cpu_arch) { 344 .aarch64 => { 345 const rel_type = @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)); 346 switch (rel_type) { 347 .ARM64_RELOC_SUBTRACTOR => { 348 // Address of the __eh_frame in the source object file 349 }, 350 .ARM64_RELOC_POINTER_TO_GOT => { 351 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false); 352 const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse 353 return error.Overflow; 354 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], result); 355 }, 356 .ARM64_RELOC_UNSIGNED => { 357 assert(rel.r_extern == 1); 358 const target_addr = try Atom.getRelocTargetAddress(zld, target, false, false); 359 const result = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)); 360 mem.writeIntLittle(i64, rec.data[rel_offset..][0..8], @as(i64, @intCast(result))); 361 }, 362 else => unreachable, 363 } 364 }, 365 .x86_64 => { 366 const rel_type = @as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type)); 367 switch (rel_type) { 368 .X86_64_RELOC_GOT => { 369 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false); 370 const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]); 371 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend)); 372 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0); 373 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], disp); 374 }, 375 else => unreachable, 376 } 377 }, 378 else => unreachable, 379 } 380 } 381 } 382 383 pub fn getCiePointerSource(rec: Record, object_id: u32, zld: *Zld, offset: u32) u32 { 384 assert(rec.tag == .fde); 385 const cpu_arch = zld.options.target.cpu.arch; 386 const addend = mem.readIntLittle(u32, rec.data[0..4]); 387 switch (cpu_arch) { 388 .aarch64 => { 389 const relocs = getRelocs(zld, object_id, offset); 390 const maybe_rel = for (relocs) |rel| { 391 if (rel.r_address - @as(i32, @intCast(offset)) == 4 and 392 @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)) == .ARM64_RELOC_SUBTRACTOR) 393 break rel; 394 } else null; 395 const rel = maybe_rel orelse return addend; 396 const object = &zld.objects.items[object_id]; 397 const target_addr = object.in_symtab.?[rel.r_symbolnum].n_value; 398 const sect = object.getSourceSection(object.eh_frame_sect_id.?); 399 return @intCast(sect.addr + offset - target_addr + addend); 400 }, 401 .x86_64 => return addend, 402 else => unreachable, 403 } 404 } 405 406 pub fn getCiePointer(rec: Record) u32 { 407 assert(rec.tag == .fde); 408 return mem.readIntLittle(u32, rec.data[0..4]); 409 } 410 411 pub fn setCiePointer(rec: *Record, ptr: u32) void { 412 assert(rec.tag == .fde); 413 mem.writeIntLittle(u32, rec.data[0..4], ptr); 414 } 415 416 pub fn getAugmentationString(rec: Record) []const u8 { 417 assert(rec.tag == .cie); 418 return mem.sliceTo(@as([*:0]const u8, @ptrCast(rec.data.ptr + 5)), 0); 419 } 420 421 pub fn getPersonalityPointer(rec: Record, ctx: struct { 422 base_addr: u64, 423 base_offset: u64, 424 }) !?u64 { 425 assert(rec.tag == .cie); 426 const aug_str = rec.getAugmentationString(); 427 428 var stream = std.io.fixedBufferStream(rec.data[9 + aug_str.len ..]); 429 var creader = std.io.countingReader(stream.reader()); 430 const reader = creader.reader(); 431 432 for (aug_str, 0..) |ch, i| switch (ch) { 433 'z' => if (i > 0) { 434 return error.BadDwarfCfi; 435 } else { 436 _ = try leb.readULEB128(u64, reader); 437 }, 438 'R' => { 439 _ = try reader.readByte(); 440 }, 441 'P' => { 442 const enc = try reader.readByte(); 443 const offset = ctx.base_offset + 13 + aug_str.len + creader.bytes_read; 444 const ptr = try getEncodedPointer(enc, @as(i64, @intCast(ctx.base_addr + offset)), reader); 445 return ptr; 446 }, 447 'L' => { 448 _ = try reader.readByte(); 449 }, 450 'S', 'B', 'G' => {}, 451 else => return error.BadDwarfCfi, 452 }; 453 454 return null; 455 } 456 457 pub fn getLsdaPointer(rec: Record, cie: Record, ctx: struct { 458 base_addr: u64, 459 base_offset: u64, 460 }) !?u64 { 461 assert(rec.tag == .fde); 462 const enc = (try cie.getLsdaEncoding()) orelse return null; 463 var stream = std.io.fixedBufferStream(rec.data[20..]); 464 const reader = stream.reader(); 465 _ = try reader.readByte(); 466 const offset = ctx.base_offset + 25; 467 const ptr = try getEncodedPointer(enc, @as(i64, @intCast(ctx.base_addr + offset)), reader); 468 return ptr; 469 } 470 471 pub fn setLsdaPointer(rec: *Record, cie: Record, value: u64, ctx: struct { 472 base_addr: u64, 473 base_offset: u64, 474 }) !void { 475 assert(rec.tag == .fde); 476 const enc = (try cie.getLsdaEncoding()) orelse unreachable; 477 var stream = std.io.fixedBufferStream(rec.data[21..]); 478 const writer = stream.writer(); 479 const offset = ctx.base_offset + 25; 480 try setEncodedPointer(enc, @as(i64, @intCast(ctx.base_addr + offset)), value, writer); 481 } 482 483 fn getLsdaEncoding(rec: Record) !?u8 { 484 assert(rec.tag == .cie); 485 const aug_str = rec.getAugmentationString(); 486 487 const base_offset = 9 + aug_str.len; 488 var stream = std.io.fixedBufferStream(rec.data[base_offset..]); 489 var creader = std.io.countingReader(stream.reader()); 490 const reader = creader.reader(); 491 492 for (aug_str, 0..) |ch, i| switch (ch) { 493 'z' => if (i > 0) { 494 return error.BadDwarfCfi; 495 } else { 496 _ = try leb.readULEB128(u64, reader); 497 }, 498 'R' => { 499 _ = try reader.readByte(); 500 }, 501 'P' => { 502 const enc = try reader.readByte(); 503 _ = try getEncodedPointer(enc, 0, reader); 504 }, 505 'L' => { 506 const enc = try reader.readByte(); 507 return enc; 508 }, 509 'S', 'B', 'G' => {}, 510 else => return error.BadDwarfCfi, 511 }; 512 513 return null; 514 } 515 516 fn getEncodedPointer(enc: u8, pcrel_offset: i64, reader: anytype) !?u64 { 517 if (enc == EH_PE.omit) return null; 518 519 var ptr: i64 = switch (enc & 0x0F) { 520 EH_PE.absptr => @as(i64, @bitCast(try reader.readIntLittle(u64))), 521 EH_PE.udata2 => @as(i16, @bitCast(try reader.readIntLittle(u16))), 522 EH_PE.udata4 => @as(i32, @bitCast(try reader.readIntLittle(u32))), 523 EH_PE.udata8 => @as(i64, @bitCast(try reader.readIntLittle(u64))), 524 EH_PE.uleb128 => @as(i64, @bitCast(try leb.readULEB128(u64, reader))), 525 EH_PE.sdata2 => try reader.readIntLittle(i16), 526 EH_PE.sdata4 => try reader.readIntLittle(i32), 527 EH_PE.sdata8 => try reader.readIntLittle(i64), 528 EH_PE.sleb128 => try leb.readILEB128(i64, reader), 529 else => return null, 530 }; 531 532 switch (enc & 0x70) { 533 EH_PE.absptr => {}, 534 EH_PE.pcrel => ptr += pcrel_offset, 535 EH_PE.datarel, 536 EH_PE.textrel, 537 EH_PE.funcrel, 538 EH_PE.aligned, 539 => return null, 540 else => return null, 541 } 542 543 return @as(u64, @bitCast(ptr)); 544 } 545 546 fn setEncodedPointer(enc: u8, pcrel_offset: i64, value: u64, writer: anytype) !void { 547 if (enc == EH_PE.omit) return; 548 549 var actual = @as(i64, @intCast(value)); 550 551 switch (enc & 0x70) { 552 EH_PE.absptr => {}, 553 EH_PE.pcrel => actual -= pcrel_offset, 554 EH_PE.datarel, 555 EH_PE.textrel, 556 EH_PE.funcrel, 557 EH_PE.aligned, 558 => unreachable, 559 else => unreachable, 560 } 561 562 switch (enc & 0x0F) { 563 EH_PE.absptr => try writer.writeIntLittle(u64, @as(u64, @bitCast(actual))), 564 EH_PE.udata2 => try writer.writeIntLittle(u16, @as(u16, @bitCast(@as(i16, @intCast(actual))))), 565 EH_PE.udata4 => try writer.writeIntLittle(u32, @as(u32, @bitCast(@as(i32, @intCast(actual))))), 566 EH_PE.udata8 => try writer.writeIntLittle(u64, @as(u64, @bitCast(actual))), 567 EH_PE.uleb128 => try leb.writeULEB128(writer, @as(u64, @bitCast(actual))), 568 EH_PE.sdata2 => try writer.writeIntLittle(i16, @as(i16, @intCast(actual))), 569 EH_PE.sdata4 => try writer.writeIntLittle(i32, @as(i32, @intCast(actual))), 570 EH_PE.sdata8 => try writer.writeIntLittle(i64, actual), 571 EH_PE.sleb128 => try leb.writeILEB128(writer, actual), 572 else => unreachable, 573 } 574 } 575 }; 576 } 577 578 pub fn getRelocs(zld: *Zld, object_id: u32, source_offset: u32) []const macho.relocation_info { 579 const object = &zld.objects.items[object_id]; 580 assert(object.hasEhFrameRecords()); 581 const urel = object.eh_frame_relocs_lookup.get(source_offset) orelse 582 return &[0]macho.relocation_info{}; 583 const all_relocs = object.getRelocs(object.eh_frame_sect_id.?); 584 return all_relocs[urel.reloc.start..][0..urel.reloc.len]; 585 } 586 587 pub const Iterator = struct { 588 data: []const u8, 589 pos: u32 = 0, 590 591 pub fn next(it: *Iterator) !?EhFrameRecord(false) { 592 if (it.pos >= it.data.len) return null; 593 594 var stream = std.io.fixedBufferStream(it.data[it.pos..]); 595 const reader = stream.reader(); 596 597 var size = try reader.readIntLittle(u32); 598 if (size == 0xFFFFFFFF) { 599 log.err("MachO doesn't support 64bit DWARF CFI __eh_frame records", .{}); 600 return error.BadDwarfCfi; 601 } 602 603 const id = try reader.readIntLittle(u32); 604 const tag: EhFrameRecordTag = if (id == 0) .cie else .fde; 605 const offset: u32 = 4; 606 const record = EhFrameRecord(false){ 607 .tag = tag, 608 .size = size, 609 .data = it.data[it.pos + offset ..][0..size], 610 }; 611 612 it.pos += size + offset; 613 614 return record; 615 } 616 617 pub fn reset(it: *Iterator) void { 618 it.pos = 0; 619 } 620 621 pub fn seekTo(it: *Iterator, pos: u32) void { 622 assert(pos >= 0 and pos < it.data.len); 623 it.pos = pos; 624 } 625 }; 626 627 pub const EH_PE = struct { 628 pub const absptr = 0x00; 629 pub const uleb128 = 0x01; 630 pub const udata2 = 0x02; 631 pub const udata4 = 0x03; 632 pub const udata8 = 0x04; 633 pub const sleb128 = 0x09; 634 pub const sdata2 = 0x0A; 635 pub const sdata4 = 0x0B; 636 pub const sdata8 = 0x0C; 637 pub const pcrel = 0x10; 638 pub const textrel = 0x20; 639 pub const datarel = 0x30; 640 pub const funcrel = 0x40; 641 pub const aligned = 0x50; 642 pub const indirect = 0x80; 643 pub const omit = 0xFF; 644 };