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

load

Public Function
std.debug.ElfFile.load
pub fn load(
    gpa: Allocator,
    io: Io,
    elf_file: Io.File,
    opt_build_id: ?[]const u8,
    di_search_paths: *const DebugInfoSearchPaths,
) LoadError!ElfFile

Params

Errors

OutOfMemory
Overflow
TruncatedElfFile
InvalidCompressedSection
InvalidElfMagic
InvalidElfVersion
InvalidElfClass
InvalidElfEndian
SystemResources

The remaining errors all occur when attemping to stat or mmap a file.

MemoryMappingNotSupported
AccessDenied
LockedMemoryLimitExceeded
ProcessFdQuotaExceeded
SystemFdQuotaExceeded
Streaming
Canceled
Unexpected

File

debug/ElfFile.zig:126
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
pub fn load(
    gpa: Allocator,
    io: Io,
    elf_file: Io.File,
    opt_build_id: ?[]const u8,
    di_search_paths: *const DebugInfoSearchPaths,
) LoadError!ElfFile {
    var arena_instance: std.heap.ArenaAllocator = .init(gpa);
    errdefer arena_instance.deinit();
    const arena = arena_instance.allocator();

    var result = loadInner(arena, io, elf_file, null) catch |err| switch (err) {
        error.CrcMismatch => unreachable, // we passed crc as null
        else => |e| return e,
    };
    errdefer std.posix.munmap(result.mapped_mem);

    // `loadInner` did most of the work, but we might need to load an external debug info file

    const di_mapped_mem: ?[]align(std.heap.page_size_min) const u8 = load_di: {
        if (result.sections.get(.debug_info) != null and
            result.sections.get(.debug_abbrev) != null and
            result.sections.get(.debug_str) != null and
            result.sections.get(.debug_line) != null)
        {
            // The info is already loaded from this file alone!
            break :load_di null;
        }

        // We're missing some debug info---let's try and load it from a separate file.

        build_id: {
            const build_id = opt_build_id orelse break :build_id;
            if (build_id.len < 3) break :build_id;

            for (di_search_paths.global_debug) |global_debug| {
                if (try loadSeparateDebugFile(arena, io, &result, null, "{s}/.build-id/{x}/{x}.debug", .{
                    global_debug,
                    build_id[0..1],
                    build_id[1..],
                })) |mapped| break :load_di mapped;
            }

            if (di_search_paths.debuginfod_client) |components| {
                if (try loadSeparateDebugFile(arena, io, &result, null, "{s}{s}/{x}/debuginfo", .{
                    components[0],
                    components[1],
                    build_id,
                })) |mapped| break :load_di mapped;
            }
        }

        debug_link: {
            const section = result.sections.get(.gnu_debuglink) orelse break :debug_link;
            const debug_filename = std.mem.sliceTo(section.bytes, 0);
            const crc_offset = std.mem.alignForward(usize, debug_filename.len + 1, 4);
            if (section.bytes.len < crc_offset + 4) break :debug_link;
            const debug_crc = std.mem.readInt(u32, section.bytes[crc_offset..][0..4], result.endian);

            const exe_dir = di_search_paths.exe_dir orelse break :debug_link;

            if (try loadSeparateDebugFile(arena, io, &result, debug_crc, "{s}/{s}", .{
                exe_dir,
                debug_filename,
            })) |mapped| break :load_di mapped;
            if (try loadSeparateDebugFile(arena, io, &result, debug_crc, "{s}/.debug/{s}", .{
                exe_dir,
                debug_filename,
            })) |mapped| break :load_di mapped;
            for (di_search_paths.global_debug) |global_debug| {
                // This looks like a bug; it isn't. They really do embed the absolute path to the
                // exe's dirname, *under* the global debug path.
                if (try loadSeparateDebugFile(arena, io, &result, debug_crc, "{s}/{s}/{s}", .{
                    global_debug,
                    exe_dir,
                    debug_filename,
                })) |mapped| break :load_di mapped;
            }
        }

        break :load_di null;
    };
    errdefer comptime unreachable;

    return .{
        .is_64 = result.is_64,
        .endian = result.endian,
        .dwarf = dwarf: {
            if (result.sections.get(.debug_info) == null or
                result.sections.get(.debug_abbrev) == null or
                result.sections.get(.debug_str) == null or
                result.sections.get(.debug_line) == null)
            {
                break :dwarf null; // debug info not present
            }
            var sections: Dwarf.SectionArray = @splat(null);
            const info = @typeInfo(Dwarf.Section.Id).@"enum";
            inline for (info.field_names, info.field_values) |f_name, f_value| {
                if (result.sections.get(@field(Section.Id, f_name))) |s| {
                    sections[f_value] = .{ .data = s.bytes, .owned = false };
                }
            }
            break :dwarf .{ .sections = sections };
        },
        .eh_frame = if (result.sections.get(.eh_frame)) |s| .{
            .vaddr = s.header.sh_addr,
            .bytes = s.bytes,
        } else null,
        .debug_frame = if (result.sections.get(.debug_frame)) |s| .{
            .vaddr = s.header.sh_addr,
            .bytes = s.bytes,
        } else null,
        .strtab = if (result.sections.get(.strtab)) |s| s.bytes else null,
        .symtab = if (result.sections.get(.symtab)) |s| .{
            .entry_size = s.header.sh_entsize,
            .bytes = s.bytes,
        } else null,
        .symbol_search_table = null,
        .mapped_file = result.mapped_mem,
        .mapped_debug_file = di_mapped_mem,
        .arena = arena_instance.state,
    };
}