Commit 7a00227253

Jakub Konka <kubkon@jakubkonka.com>
2022-04-14 15:15:09
elf: support --strip option
When the user passes `--strip` option on the command line, we do not emit any debug info by skipping initializing the internal `Dwarf` module.
1 parent 2a00df9
Changed files (1)
src
link
src/link/Elf.zig
@@ -100,11 +100,11 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
 phdr_table_dirty: bool = false,
 shdr_table_dirty: bool = false,
 shstrtab_dirty: bool = false,
-debug_strtab_dirty: bool = false,
 offset_table_count_dirty: bool = false,
+
+debug_strtab_dirty: bool = false,
 debug_abbrev_section_dirty: bool = false,
 debug_aranges_section_dirty: bool = false,
-
 debug_info_header_dirty: bool = false,
 debug_line_header_dirty: bool = false,
 
@@ -749,127 +749,129 @@ pub fn populateMissingMetadata(self: *Elf) !void {
         try self.writeSymbol(0);
     }
 
-    if (self.debug_str_section_index == null) {
-        self.debug_str_section_index = @intCast(u16, self.sections.items.len);
-        assert(self.dwarf.?.strtab.items.len == 0);
-        try self.sections.append(self.base.allocator, .{
-            .sh_name = try self.makeString(".debug_str"),
-            .sh_type = elf.SHT_PROGBITS,
-            .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
-            .sh_addr = 0,
-            .sh_offset = 0,
-            .sh_size = 0,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = 1,
-            .sh_entsize = 1,
-        });
-        self.debug_strtab_dirty = true;
-        self.shdr_table_dirty = true;
-    }
+    if (self.dwarf) |dw| {
+        if (self.debug_str_section_index == null) {
+            self.debug_str_section_index = @intCast(u16, self.sections.items.len);
+            assert(dw.strtab.items.len == 0);
+            try self.sections.append(self.base.allocator, .{
+                .sh_name = try self.makeString(".debug_str"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
+                .sh_addr = 0,
+                .sh_offset = 0,
+                .sh_size = 0,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = 1,
+                .sh_entsize = 1,
+            });
+            self.debug_strtab_dirty = true;
+            self.shdr_table_dirty = true;
+        }
 
-    if (self.debug_info_section_index == null) {
-        self.debug_info_section_index = @intCast(u16, self.sections.items.len);
+        if (self.debug_info_section_index == null) {
+            self.debug_info_section_index = @intCast(u16, self.sections.items.len);
 
-        const file_size_hint = 200;
-        const p_align = 1;
-        const off = self.findFreeSpace(file_size_hint, p_align);
-        log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
-            off,
-            off + file_size_hint,
-        });
-        try self.sections.append(self.base.allocator, .{
-            .sh_name = try self.makeString(".debug_info"),
-            .sh_type = elf.SHT_PROGBITS,
-            .sh_flags = 0,
-            .sh_addr = 0,
-            .sh_offset = off,
-            .sh_size = file_size_hint,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = p_align,
-            .sh_entsize = 0,
-        });
-        self.shdr_table_dirty = true;
-        self.debug_info_header_dirty = true;
-    }
+            const file_size_hint = 200;
+            const p_align = 1;
+            const off = self.findFreeSpace(file_size_hint, p_align);
+            log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
+                off,
+                off + file_size_hint,
+            });
+            try self.sections.append(self.base.allocator, .{
+                .sh_name = try self.makeString(".debug_info"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
+            });
+            self.shdr_table_dirty = true;
+            self.debug_info_header_dirty = true;
+        }
 
-    if (self.debug_abbrev_section_index == null) {
-        self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
+        if (self.debug_abbrev_section_index == null) {
+            self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
 
-        const file_size_hint = 128;
-        const p_align = 1;
-        const off = self.findFreeSpace(file_size_hint, p_align);
-        log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
-            off,
-            off + file_size_hint,
-        });
-        try self.sections.append(self.base.allocator, .{
-            .sh_name = try self.makeString(".debug_abbrev"),
-            .sh_type = elf.SHT_PROGBITS,
-            .sh_flags = 0,
-            .sh_addr = 0,
-            .sh_offset = off,
-            .sh_size = file_size_hint,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = p_align,
-            .sh_entsize = 0,
-        });
-        self.shdr_table_dirty = true;
-        self.debug_abbrev_section_dirty = true;
-    }
+            const file_size_hint = 128;
+            const p_align = 1;
+            const off = self.findFreeSpace(file_size_hint, p_align);
+            log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
+                off,
+                off + file_size_hint,
+            });
+            try self.sections.append(self.base.allocator, .{
+                .sh_name = try self.makeString(".debug_abbrev"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
+            });
+            self.shdr_table_dirty = true;
+            self.debug_abbrev_section_dirty = true;
+        }
 
-    if (self.debug_aranges_section_index == null) {
-        self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
+        if (self.debug_aranges_section_index == null) {
+            self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
 
-        const file_size_hint = 160;
-        const p_align = 16;
-        const off = self.findFreeSpace(file_size_hint, p_align);
-        log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
-            off,
-            off + file_size_hint,
-        });
-        try self.sections.append(self.base.allocator, .{
-            .sh_name = try self.makeString(".debug_aranges"),
-            .sh_type = elf.SHT_PROGBITS,
-            .sh_flags = 0,
-            .sh_addr = 0,
-            .sh_offset = off,
-            .sh_size = file_size_hint,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = p_align,
-            .sh_entsize = 0,
-        });
-        self.shdr_table_dirty = true;
-        self.debug_aranges_section_dirty = true;
-    }
+            const file_size_hint = 160;
+            const p_align = 16;
+            const off = self.findFreeSpace(file_size_hint, p_align);
+            log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
+                off,
+                off + file_size_hint,
+            });
+            try self.sections.append(self.base.allocator, .{
+                .sh_name = try self.makeString(".debug_aranges"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
+            });
+            self.shdr_table_dirty = true;
+            self.debug_aranges_section_dirty = true;
+        }
 
-    if (self.debug_line_section_index == null) {
-        self.debug_line_section_index = @intCast(u16, self.sections.items.len);
+        if (self.debug_line_section_index == null) {
+            self.debug_line_section_index = @intCast(u16, self.sections.items.len);
 
-        const file_size_hint = 250;
-        const p_align = 1;
-        const off = self.findFreeSpace(file_size_hint, p_align);
-        log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
-            off,
-            off + file_size_hint,
-        });
-        try self.sections.append(self.base.allocator, .{
-            .sh_name = try self.makeString(".debug_line"),
-            .sh_type = elf.SHT_PROGBITS,
-            .sh_flags = 0,
-            .sh_addr = 0,
-            .sh_offset = off,
-            .sh_size = file_size_hint,
-            .sh_link = 0,
-            .sh_info = 0,
-            .sh_addralign = p_align,
-            .sh_entsize = 0,
-        });
-        self.shdr_table_dirty = true;
-        self.debug_line_header_dirty = true;
+            const file_size_hint = 250;
+            const p_align = 1;
+            const off = self.findFreeSpace(file_size_hint, p_align);
+            log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
+                off,
+                off + file_size_hint,
+            });
+            try self.sections.append(self.base.allocator, .{
+                .sh_name = try self.makeString(".debug_line"),
+                .sh_type = elf.SHT_PROGBITS,
+                .sh_flags = 0,
+                .sh_addr = 0,
+                .sh_offset = off,
+                .sh_size = file_size_hint,
+                .sh_link = 0,
+                .sh_info = 0,
+                .sh_addralign = p_align,
+                .sh_entsize = 0,
+            });
+            self.shdr_table_dirty = true;
+            self.debug_line_header_dirty = true;
+        }
     }
 
     const shsize: u64 = switch (self.ptr_width) {
@@ -1001,40 +1003,42 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
     // mixing local and global symbols within a symbol table.
     try self.writeAllGlobalSymbols();
 
-    if (self.debug_abbrev_section_dirty) {
-        try self.dwarf.?.writeDbgAbbrev(&self.base);
-        if (!self.shdr_table_dirty) {
-            // Then it won't get written with the others and we need to do it.
-            try self.writeSectHeader(self.debug_abbrev_section_index.?);
+    if (self.dwarf) |*dw| {
+        if (self.debug_abbrev_section_dirty) {
+            try dw.writeDbgAbbrev(&self.base);
+            if (!self.shdr_table_dirty) {
+                // Then it won't get written with the others and we need to do it.
+                try self.writeSectHeader(self.debug_abbrev_section_index.?);
+            }
+            self.debug_abbrev_section_dirty = false;
         }
-        self.debug_abbrev_section_dirty = false;
-    }
 
-    if (self.debug_info_header_dirty) {
-        // Currently only one compilation unit is supported, so the address range is simply
-        // identical to the main program header virtual address and memory size.
-        const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
-        const low_pc = text_phdr.p_vaddr;
-        const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
-        try self.dwarf.?.writeDbgInfoHeader(&self.base, module, low_pc, high_pc);
-        self.debug_info_header_dirty = false;
-    }
+        if (self.debug_info_header_dirty) {
+            // Currently only one compilation unit is supported, so the address range is simply
+            // identical to the main program header virtual address and memory size.
+            const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+            const low_pc = text_phdr.p_vaddr;
+            const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
+            try dw.writeDbgInfoHeader(&self.base, module, low_pc, high_pc);
+            self.debug_info_header_dirty = false;
+        }
 
-    if (self.debug_aranges_section_dirty) {
-        // Currently only one compilation unit is supported, so the address range is simply
-        // identical to the main program header virtual address and memory size.
-        const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
-        try self.dwarf.?.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz);
-        if (!self.shdr_table_dirty) {
-            // Then it won't get written with the others and we need to do it.
-            try self.writeSectHeader(self.debug_aranges_section_index.?);
+        if (self.debug_aranges_section_dirty) {
+            // Currently only one compilation unit is supported, so the address range is simply
+            // identical to the main program header virtual address and memory size.
+            const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
+            try dw.writeDbgAranges(&self.base, text_phdr.p_vaddr, text_phdr.p_memsz);
+            if (!self.shdr_table_dirty) {
+                // Then it won't get written with the others and we need to do it.
+                try self.writeSectHeader(self.debug_aranges_section_index.?);
+            }
+            self.debug_aranges_section_dirty = false;
         }
-        self.debug_aranges_section_dirty = false;
-    }
 
-    if (self.debug_line_header_dirty) {
-        try self.dwarf.?.writeDbgLineHeader(&self.base, module);
-        self.debug_line_header_dirty = false;
+        if (self.debug_line_header_dirty) {
+            try dw.writeDbgLineHeader(&self.base, module);
+            self.debug_line_header_dirty = false;
+        }
     }
 
     if (self.phdr_table_dirty) {
@@ -1105,9 +1109,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
         }
     }
 
-    {
+    if (self.dwarf) |dwarf| {
         const debug_strtab_sect = &self.sections.items[self.debug_str_section_index.?];
-        const dwarf = self.dwarf.?;
         if (self.debug_strtab_dirty or dwarf.strtab.items.len != debug_strtab_sect.sh_size) {
             const allocated_size = self.allocatedSize(debug_strtab_sect.sh_offset);
             const needed_size = dwarf.strtab.items.len;
@@ -2105,14 +2108,16 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
         phdr.p_memsz = needed_size;
         phdr.p_filesz = needed_size;
 
-        // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
-        // range of the compilation unit. When we expand the text section, this range changes,
-        // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
-        self.debug_info_header_dirty = true;
-        // This becomes dirty for the same reason. We could potentially make this more
-        // fine-grained with the addition of support for more compilation units. It is planned to
-        // model each package as a different compilation unit.
-        self.debug_aranges_section_dirty = true;
+        if (self.dwarf) |_| {
+            // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
+            // range of the compilation unit. When we expand the text section, this range changes,
+            // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
+            self.debug_info_header_dirty = true;
+            // This becomes dirty for the same reason. We could potentially make this more
+            // fine-grained with the addition of support for more compilation units. It is planned to
+            // model each package as a different compilation unit.
+            self.debug_aranges_section_dirty = true;
+        }
 
         self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
         self.shdr_table_dirty = true; // TODO look into making only the one section dirty