Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Public Function

prepare

Public Function
std.debug.Dwarf.Unwind.prepare
pub fn prepare(
    unwind: *Unwind,
    gpa: Allocator,
    addr_size_bytes: u8,
    endian: Endian,
    need_lookup: bool,
    /// The `__eh_frame` section in Mach-O binaries deviates from the standard `.eh_frame` section
    /// in one way which this function needs to be aware of.
    is_macho: bool,
) !void

Builds the CIE list and FDE lookup table if they are not already built. It is required to call this function at least once before calling lookupPc or getFde. If only getFde is needed, then need_lookup can be set to false to make this function more efficient.

Params

  • unwind: *Unwind
  • gpa: Allocator
  • addr_size_bytes: u8
  • endian: Endian
  • need_lookup: bool
  • is_macho: bool

    The __eh_frame section in Mach-O binaries deviates from the standard .eh_frame section in one way which this function needs to be aware of.

File

debug/Dwarf/Unwind.zig:471
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
pub fn prepare(
    unwind: *Unwind,
    gpa: Allocator,
    addr_size_bytes: u8,
    endian: Endian,
    need_lookup: bool,
    /// The `__eh_frame` section in Mach-O binaries deviates from the standard `.eh_frame` section
    /// in one way which this function needs to be aware of.
    is_macho: bool,
) !void {
    if (unwind.cie_list.len > 0 and (!need_lookup or unwind.lookup != null)) return;
    unwind.cie_list.clearRetainingCapacity();

    if (is_macho) assert(unwind.lookup == null or unwind.lookup.? != .eh_frame_hdr);

    const section = unwind.frame_section;

    var r: Reader = .fixed(section.bytes);
    var fde_list: std.ArrayList(SortedFdeEntry) = .empty;
    defer fde_list.deinit(gpa);

    const saw_terminator = while (r.seek < r.buffer.len) {
        const entry_offset = r.seek;
        switch (try EntryHeader.read(&r, entry_offset, section.id, endian)) {
            .cie => |cie_info| {
                // We will pre-populate a list of CIEs for efficiency: this avoids work re-parsing
                // them every time we look up an FDE. It also lets us cache the result of evaluating
                // the CIE's initial CFI instructions, which is useful because in the vast majority
                // of cases those instructions will be needed to reach the PC we are unwinding to.
                const bytes_len = cast(usize, cie_info.bytes_len) orelse return error.EndOfStream;
                const idx = unwind.cie_list.len;
                try unwind.cie_list.append(gpa, .{
                    .offset = entry_offset,
                    .cie = CommonInformationEntry.parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes) catch |err| switch (err) {
                        error.UnsupportedDwarfVersion,
                        error.UnsupportedAugmentation,
                        => {
                            // These are recoverable by just skipping the CIE.
                            continue;
                        },
                        else => |e| return e,
                    },
                });
                errdefer _ = unwind.cie_list.pop().?;
                try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian);
                continue;
            },
            .fde => |fde_info| {
                const bytes_len = cast(usize, fde_info.bytes_len) orelse return error.EndOfStream;
                if (!need_lookup) {
                    try r.discardAll(bytes_len);
                    continue;
                }
                const fde_vaddr = section.vaddr + r.seek;
                const fde_bytes = try r.take(bytes_len);
                const cie = unwind.findCie(fde_info.cie_offset) orelse continue;
                const fde: FrameDescriptionEntry = try .parse(fde_vaddr, fde_bytes, cie, endian);
                try fde_list.append(gpa, .{
                    .pc_begin = fde.pc_begin,
                    .fde_offset = entry_offset,
                });
            },
            .terminator => break true,
        }
    } else false;
    const expect_terminator = switch (section.id) {
        .eh_frame => !is_macho, // `.eh_frame` indicates the end of the CIE/FDE list with a sentinel entry, though macOS omits this
        .debug_frame => false, // `.debug_frame` uses the section bounds and does not specify a sentinel entry
    };
    if (saw_terminator != expect_terminator) return bad();

    if (need_lookup) {
        std.mem.sortUnstable(SortedFdeEntry, fde_list.items, {}, struct {
            fn lessThan(ctx: void, a: SortedFdeEntry, b: SortedFdeEntry) bool {
                ctx;
                return a.pc_begin < b.pc_begin;
            }
        }.lessThan);

        // This temporary is necessary to avoid an RLS footgun where `lookup` ends up non-null `undefined` on OOM.
        const final_fdes = try fde_list.toOwnedSlice(gpa);
        unwind.lookup = .{ .sorted_fdes = final_fdes };
    }
}