[PATCH 6/6] doc: Add elf_compress.3 and elf_compress_gnu.3
Signed-off-by: Aaron Merey --- doc/Makefile.am| 2 + doc/elf_compress.3 | 183 + doc/elf_compress_gnu.3 | 1 + 3 files changed, 186 insertions(+) create mode 100644 doc/elf_compress.3 create mode 100644 doc/elf_compress_gnu.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index de0106bb..aaf90606 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -52,6 +52,8 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf_begin.3 \ elf_clone.3 \ elf_cntl.3 \ + elf_compress.3 \ + elf_compress_gnu.3 \ elf_end.3 \ elf_errmsg.3 \ elf_errno.3 \ diff --git a/doc/elf_compress.3 b/doc/elf_compress.3 new file mode 100644 index ..df48336a --- /dev/null +++ b/doc/elf_compress.3 @@ -0,0 +1,183 @@ +.TH ELF_COMPRESS 3 2025-06-09 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_compress, elf_compress_gnu \- compress or decompress a section in an ELF object +.SH SYNOPSIS +.nf +#include + +.BI "int elf_compress (Elf_Scn *" scn ", int" type ", unsigned int "flags"); +.BI "int elf_compress_gnu (Elf_Scn *" scn ", int" compress ", unsigned int" flags "); +.fi +.SH DESCRIPTION +The functions +.BR elf_compress () +and +.BR elf_compress_gnu () +modify the contents of a section in an ELF descriptor by compressing or +decompressing the section data and adjusting the section header. These changes +take effect when the ELF descriptor is written with +.BR elf_update (3). +These functions do not mark the section as dirty. To retain the changes in +.B elf_update(), +call +.BR elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY) . + +.BR elf_compress () +works by setting or clearing the +.B SHF_COMPRESSED +flag in the section header and will encode or decode an +.B Elf32_Chdr +or +.B Elf64_Chdr +structure at the start of the section data. + +.BR elf_compress_gnu () +can encode or decode any section, but is traditionally used only for sections whose names begin with +.B .debug +when uncompressed or +.B .zdebug +when compressed. It stores only the uncompressed size followed by the compressed payload. The GNU compression method is deprecated and should be used only for legacy support. + +.BR elf_compress_gnu () +does not check whether the section name begins with +.B .debug +or +.B .zdebug . +It is the responsibility of the caller to ensure that the deprecated GNU compression method is used only on appropriately named sections, and to rename the section if necessary when using +.BR elf_compress_gnu () . + +These functions invalidate all previously returned section headers and +.B Elf_Data +buffers for the affected section. The caller must not use these stale pointers +after invoking either function. + +The section must not be of type +.B SHT_NOBITS +and must not have the +.B SHF_ALLOC +flag set. Using these functions on such sections results in an error. + +Calling +.B elf_compress_gnu() +on a section with the +.B SHF_COMPRESSED +flag set is an error. The section must first be decompressed using +.B elf_compress (scn, 0, 0) +before applying GNU-style compression. + +.SH PARAMETERS +.SS elf_compress +.TP +.I scn +A pointer to an +.B Elf_Scn +structure representing the section to compress or decompress. Must not be NULL. The section must not be of type +.B SHT_NOBITS +and must not have the +.B SHF_ALLOC +flag set. + +.TP +.I type +Specifies the compression algorithm or decompression mode. Valid values are: +.RS +.TP +.B 0 +Decompress the section. The section must currently have the +.B SHF_COMPRESSED +flag set. +.TP +.B ELFCOMPRESS_ZLIB +Compress the section using the ZLIB/DEFLATE algorithm. +.TP +.B ELFCOMPRESS_ZSTD +Compress the section using the Zstandard algorithm. +.TP +.B ELFCOMPRESS_LOOS +Start of the OS-specific compression algorithm range. +.TP +.B ELFCOMPRESS_HIOS +End of the OS-specific compression algorithm range. +.TP +.B ELFCOMPRESS_LOPROC +Start of the processor-specific compression algorithm range. +.TP +.B ELFCOMPRESS_HIPROC +End of the processor-specific compression algorithm range. +.RE + +.TP +.I flags +May be zero or: +.RS +.TP +.B ELF_CHF_FORCE +Force compression even if it does not reduce the total size of the section (including any headers). +.RE + +.SS elf_compress_gnu +.TP +.I scn +Same as above. The section must not have the +.B SHF_COMPRESSED +flag set and must not be of type +.B SHT_NOBITS +or have the +.B SHF_ALLOC +flag set. + +.TP +.I compress +Set to 1 to compress using the legacy GNU format, or 0 to decompress. + +.TP +.I flags +Same as for +.BR elf_compress () . + +.SH RETURN VALUE +Both functions return: + +.TP +.B 1 +The section was successfully compressed or decompressed. + +.TP +.B 0 +Compression was requested but skipped because the result would not reduce size and +.B ELF_CHF_FORCE +was not set. + +.TP +.B \-1 +An error occurred. The error code can be retr
[PATCH 4/6 v2] doc: Add elf_getarsym.3
Signed-off-by: Aaron Merey --- v2: Clarify that narsyms can be NULL and that the end of the archive symbol table contains a special NULL entry. doc/Makefile.am| 1 + doc/elf_getarsym.3 | 99 ++ 2 files changed, 100 insertions(+) create mode 100644 doc/elf_getarsym.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index aae29ebc..d0ec20da 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -57,6 +57,7 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf_fill.3 \ elf_getarhdr.3 \ elf_getaroff.3 \ + elf_getarsym.3 \ elf_getbase.3 \ elf_getdata.3 \ elf_getscn.3 \ diff --git a/doc/elf_getarsym.3 b/doc/elf_getarsym.3 new file mode 100644 index ..14bcae32 --- /dev/null +++ b/doc/elf_getarsym.3 @@ -0,0 +1,99 @@ +.TH ELF_GETARSYM 3 2025-06-06 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_getarsym \- retrieve archive symbol table + +.SH SYNOPSIS +.nf +.B #include + +.BI "Elf_Arsym *elf_getarsym(Elf *" elf ", size_t *" narsyms );" +.fi + +.SH DESCRIPTION +Retrieve the archive symbol table from the archive file associated with +.IR elf . + +.P +If the archive contains a symbol table, +.B elf_getarsym() +returns a pointer to an array of +.B Elf_Arsym +structures describing each symbol. Also store the number of symbols in this +array in +.I narsyms +if not NULL. + +.B Elf_Arsym +has the following layout: + +.P +.nf +typedef struct { + char *as_name; /* Symbol name (null-terminated). */ + int64_t as_off;/* File offset of defining archive member. */ + uint64_t as_hash; /* Hash value of symbol name. */ +} Elf_Arsym; +.fi + +The last entry in the archive symbol table is the special entry +{ NULL, 0, ~0L}. This can be used to find the end of the table if +.I narsyms +is NULL. + +.SH PARAMETERS +.TP +.I elf +An ELF descriptor referring to an archive file, obtained by calling +.BR elf_begin (3) +on an archive. + +.TP +.I narsyms +A pointer to a +.B size_t +in which the number of entries in the symbol table will be stored +if this pointer is not NULL. + +.SH RETURN VALUE +If the archive contains a symbol table, return a pointer to an array of +.B Elf_Arsym +structures, including the special NULL entry indicating the the end of the +table. Sets +.I *narsyms +to the number of entries in the array (if +.I narsyms +is not NULL). These pointers are managed by libelf and should not be freed +by the caller of +.BR elf_getarsym . + +.P +If the archive does not contain a symbol table or +.I elf +is not a valid archive descriptor, +.B elf_getarsym +returns +.B NULL. + +.SH SEE ALSO +.BR elf_begin (3), +.BR elf_getarhdr (3), +.BR elf_next (3), +.BR libelf (3), +.BR elf (5) + +.SH ATTRIBUTES +.TS +allbox; +lbx lb lb +l l l. +Interface Attribute Value +T{ +.na +.nh +.BR elf_getarsym () +T} Thread safety MT-Safe +.TE + +.SH REPORTING BUGS +Report bugs to or https://sourceware.org/bugzilla/. -- 2.49.0
[PATCH 5/6] doc: Add elf_cntl.3
Signed-off-by: Aaron Merey --- doc/Makefile.am | 1 + doc/elf_cntl.3 | 66 + 2 files changed, 67 insertions(+) create mode 100644 doc/elf_cntl.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index d0ec20da..de0106bb 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -51,6 +51,7 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf64_xlatetom.3 \ elf_begin.3 \ elf_clone.3 \ + elf_cntl.3 \ elf_end.3 \ elf_errmsg.3 \ elf_errno.3 \ diff --git a/doc/elf_cntl.3 b/doc/elf_cntl.3 new file mode 100644 index ..2ef3e6b9 --- /dev/null +++ b/doc/elf_cntl.3 @@ -0,0 +1,66 @@ +.TH ELF_CNTL 3 2025-06-17 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_cntl \- perform control operations on an ELF descriptor + +.SH SYNOPSIS +.nf +#include + +int elf_cntl(Elf *elf, Elf_Cmd cmd); +.fi +.SH DESCRIPTION +Perform control operations on the ELF descriptor +.I elf +according to the operation specified by +.IR cmd . + +The following commands are supported: + +.TP +.B ELF_C_FDDONE +This command tells +.B libelf +that the application is done using the file descriptor associated with the +.I elf +object. The file descriptor may then be closed immediately without affecting the +in-memory ELF data. + +.TP +.B ELF_C_FDREAD +This command causes +.B libelf +to read the entire contents of the underlying file into memory immediately. +.B libelf +generally reads and parses elements of ELF files only when they are required. +This command instead triggers +.B libelf +to read all elements immediately. + +.SH RETURN VALUE +On success, returns 0. + +On failure, it returns \-1 and sets an error that can be retrieved with +.BR elf_errmsg (3). + + +.SH SEE ALSO +.BR libelf (3), +.BR elf_errmsg (3), +.BR elf (5) + +.SH ATTRIBUTES +.TS +allbox; +lbx lb lb +l l l. +Interface Attribute Value +T{ +.na +.nh +.BR elf_cntl () +T} Thread safety MT-Safe +.TE + +.SH REPORTING BUGS +Report bugs to or https://sourceware.org/bugzilla/. -- 2.49.0
[PATCH] libdwP.h: Remove abbrev_lock
Improve __libdw_dieabbrev performance by removing abbrev_lock. This lock protects the Dwarf_Die abbrev member due to lazy loading. Instead, eagerly load abbrev during Dwarf_Die initialization so that the member is readonly and requires no locking. Signed-off-by: Aaron Merey --- libdw/dwarf_decl_file.c | 3 +- libdw/dwarf_end.c | 1 - libdw/dwarf_getscopevar.c | 3 +- libdw/libdwP.h| 65 +-- libdw/libdw_findcu.c | 1 - 5 files changed, 32 insertions(+), 41 deletions(-) diff --git a/libdw/dwarf_decl_file.c b/libdw/dwarf_decl_file.c index 1b91a4e9..03040e12 100644 --- a/libdw/dwarf_decl_file.c +++ b/libdw/dwarf_decl_file.c @@ -50,7 +50,8 @@ dwarf_decl_file (Dwarf_Die *die) Dwarf_Files *files; size_t nfiles; - if (INTUSE(dwarf_getsrcfiles) (&CUDIE (attr_mem.cu), &files, &nfiles) != 0) + Dwarf_Die cudie = CUDIE (attr_mem.cu); + if (INTUSE(dwarf_getsrcfiles) (&cudie, &files, &nfiles) != 0) return NULL; if (idx >= nfiles) diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index 1628e448..51021d64 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -68,7 +68,6 @@ cu_free (void *arg) && p != p->dbg->fake_addr_cu) { Dwarf_Abbrev_Hash_free (&p->abbrev_hash); - rwlock_fini (p->abbrev_lock); rwlock_fini (p->split_lock); mutex_fini (p->src_lock); mutex_fini (p->str_off_base_lock); diff --git a/libdw/dwarf_getscopevar.c b/libdw/dwarf_getscopevar.c index 7b1416f3..306ccae0 100644 --- a/libdw/dwarf_getscopevar.c +++ b/libdw/dwarf_getscopevar.c @@ -40,7 +40,8 @@ static int getfiles (Dwarf_Die *die, Dwarf_Files **files) { - return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL); + Dwarf_Die cudie = CUDIE (die->cu); + return INTUSE(dwarf_getsrcfiles) (&cudie, files, NULL); } /* Fetch an attribute that should have a constant integer form. */ diff --git a/libdw/libdwP.h b/libdw/libdwP.h index de80cd4e..4a528c9c 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -455,10 +455,6 @@ struct Dwarf_CU Don't access directly, call __libdw_cu_locs_base. */ Dwarf_Off locs_base; - /* Synchronize access to the abbrev member of a Dwarf_Die that - refers to this Dwarf_CU. Covers __libdw_die_abbrev. */ - rwlock_define(, abbrev_lock); - /* Synchronize access to the split member of this Dwarf_CU. Covers __libdw_find_split_unit. */ rwlock_define(, split_lock); @@ -595,23 +591,6 @@ __libdw_first_die_off_from_cu (struct Dwarf_CU *cu) cu->unit_type); } -#define CUDIE(fromcu)\ - ((Dwarf_Die) \ - { \ - .cu = (fromcu), \ - .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \ - + __libdw_first_die_off_from_cu (fromcu)) \ - }) - -#define SUBDIE(fromcu) \ - ((Dwarf_Die) \ - { \ - .cu = (fromcu), \ - .addr = ((char *) (fromcu)->dbg->sectiondata[cu_sec_idx (fromcu)]->d_buf \ - + (fromcu)->start + (fromcu)->subdie_offset)\ - }) - - /* Prototype of a single .debug_macro operator. */ typedef struct { @@ -820,12 +799,7 @@ __nonnull_attribute__ (1) __libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp) { if (unlikely (die->cu == NULL)) -{ - die->abbrev = DWARF_END_ABBREV; - return DWARF_END_ABBREV; -} - - rwlock_wrlock (die->cu->abbrev_lock); +return DWARF_END_ABBREV; /* Do we need to get the abbreviation, or need to read after the code? */ if (die->abbrev == NULL || readp != NULL) @@ -835,25 +809,20 @@ __libdw_dieabbrev (Dwarf_Die *die, const unsigned char **readp) const unsigned char *addr = die->addr; if (addr >= (const unsigned char *) die->cu->endp) - { - die->abbrev = DWARF_END_ABBREV; - rwlock_unlock (die->cu->abbrev_lock); - return DWARF_END_ABBREV; - } + return DWARF_END_ABBREV; get_uleb128 (code, addr, die->cu->endp); if (readp != NULL) *readp = addr; - /* Find the abbreviation. */ + /* Find the abbreviation. To improve performance, this write is not +protected by a lock. It should only be reachable by a single thread +when initializing the DIE. */ if (die->abbrev == NULL) die->abbrev = __libdw_findabbrev (die->cu, code); } - Dwarf_Abbrev *result = die->abbrev; - rwlock_unlock (die->cu->abbrev_lock); - - return result; + return die->a
[PATCH] libdwl: Add validate_strdata to limit Elf_Data d_size to valid strings.
dwfl_module_getsym returns the name of a symbol as found in the corresponding (symbol) string section. Make sure all names are correctly zero terminated by making sure the last valid index in a section/segment Elf_Data contains a zero character. * libdwfl/dwfl_module_getdwarf.c (validate_strdata): New function taking Elf_Data and restricting d_size to last zero char. (translate_offs): Call validate_strdata. (find_symtab): Likewise for both symstrdata and aux_symstrdata. https://sourceware.org/bugzilla/show_bug.cgi?id=33099 Signed-off-by: Mark Wielaard --- libdwfl/dwfl_module_getdwarf.c | 20 1 file changed, 20 insertions(+) diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 7fd0d3aa3b17..135132d69178 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1,5 +1,6 @@ /* Find debugging and symbol information for a module in libdwfl. Copyright (C) 2005-2012, 2014, 2015, 2025 Red Hat, Inc. + Copyright (C) 2025 Mark J. Wielaard This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -692,6 +693,19 @@ find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, } } +/* This is a string section/segment, so we want to make sure the last + valid index contains a zero character to terminate a string. */ +static void +validate_strdata (Elf_Data *symstrdata) +{ + size_t size = symstrdata->d_size; + const char *buf = symstrdata->d_buf; + while (size > 0 && *(buf + size - 1) != '\0') +--size; + symstrdata->d_size = size; +} + + /* Various addresses we might want to pull from the dynamic segment. */ enum { @@ -816,6 +830,8 @@ translate_offs (GElf_Addr adjust, ELF_T_BYTE); if (mod->symstrdata == NULL) mod->symdata = NULL; + else + validate_strdata (mod->symstrdata); } if (mod->symdata == NULL) mod->symerr = DWFL_E (LIBELF, elf_errno ()); @@ -1181,6 +1197,8 @@ find_symtab (Dwfl_Module *mod) mod->symstrdata = elf_getdata (symstrscn, NULL); if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL) goto elferr; + else +validate_strdata (mod->symstrdata); if (xndxscn == NULL) mod->symxndxdata = NULL; @@ -1264,6 +1282,8 @@ find_symtab (Dwfl_Module *mod) mod->aux_symstrdata = elf_getdata (aux_strscn, NULL); if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL) goto aux_cleanup; + else + validate_strdata (mod->aux_symstrdata); if (aux_xndxscn == NULL) mod->aux_symxndxdata = NULL; -- 2.49.0
[PATCH 1/6 v2] doc: Add elf_next.3
Signed-off-by: Aaron Merey --- v2: Clarify that elf_next is called with an archive member in order to update the descriptor for the parent archive. Added a code example. doc/Makefile.am | 1 + doc/elf_next.3 | 120 2 files changed, 121 insertions(+) create mode 100644 doc/elf_next.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index 1ced7858..fbfebfe0 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -61,6 +61,7 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf_hash.3 \ elf_kind.3 \ elf_ndxscn.3 \ + elf_next.3 \ elf_update.3 \ elf_version.3 \ libelf.3 diff --git a/doc/elf_next.3 b/doc/elf_next.3 new file mode 100644 index ..1e3f0ee5 --- /dev/null +++ b/doc/elf_next.3 @@ -0,0 +1,120 @@ +.TH ELF_NEXT 3 2025-06-06 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_next \- advance an ELF descriptor to the next archive member + +.SH SYNOPSIS +.nf +.B #include + +.BI "Elf_Cmd elf_next(Elf *" elf ");" +.fi +.SH DESCRIPTION +Advance an ELF descriptor associated with an archive file to the next available +archive member. + +.P +ELF descriptors initialized from an archive file can be used to retrieve ELF +descriptors for archive members one at a time using +.BR elf_begin . +.B elf_next +updates the archive descriptor so that +.B elf_begin +may return the ELF descriptor of the next member of the archive. +.B elf_next +is called with a archive member's ELF descriptor and updates descriptor +of the parent archive (see the EXAMPLES section below). + +.SH RETURN VALUE +If +.I elf +refers to an archive member, update the state of the parent archive +ELF descriptor associated with +.I elf +so that the next archive member can be retrieved with +.BR elf_begin . +Return the +.B Elf_Cmd +that was used with +.B elf_begin +to initialize +.IR elf . + +.P +If +.I elf +was not initialized from an archive file or there are no more archive members, +.B elf_next +returns +.B ELF_C_NULL. + +.SH EXAMPLES +.nf + /* Open the archive. */ + fd = open (archive_name, O_RDONLY); + if (fd == -1) +{ + printf ("cannot open archive file `%s'", fname); + exit (1); +} + + /* Set the ELF version. */ + elf_version (EV_CURRENT); + + /* Create an ELF descriptor for the archive. */ + cmd = ELF_C_READ; + elf = elf_begin (fd, cmd, NULL); + if (elf == NULL) +{ + printf ("cannot create ELF descriptor: %s\\n", elf_errmsg (-1)); + exit (1); +} + + /* Verify this is a descriptor for an archive. */ + if (elf_kind (elf) != ELF_K_AR) +{ + printf ("`%s' is not an archive\\n", fname); + exit (1); +} + + /* Get the members of the archive one after the other. */ + while ((subelf = elf_begin (fd, cmd, elf)) != NULL) +{ + /* Process subelf here */ + [...] + + /* Get next archive element. */ + cmd = elf_next (subelf); + if (elf_end (subelf) != 0) +{ + printf ("error while freeing sub-ELF descriptor: %s\\n", + elf_errmsg (-1)); + exit (1); +} +} + + elf_end (elf); + close (fd); +.fi + +.SH SEE ALSO +.BR elf_begin (3), +.BR elf_rand (3), +.BR libelf (3), +.BR elf (5) + +.SH ATTRIBUTES +.TS +allbox; +lbx lb lb +l l l. +Interface Attribute Value +T{ +.na +.nh +.BR elf_next () +T} Thread safety MT-Safe +.TE + +.SH REPORTING BUGS +Report bugs to or https://sourceware.org/bugzilla/. -- 2.49.0
[Bug libelf/33099] heap overflow in print_dwarf_addr
https://sourceware.org/bugzilla/show_bug.cgi?id=33099 Mark Wielaard changed: What|Removed |Added Status|NEW |ASSIGNED --- Comment #4 from Mark Wielaard --- (In reply to Mark Wielaard from comment #3) > Or maybe we need to add the check where the symstrdata is allocated? I wrote a patch to do that instead: https://code.wildebeest.org/git/user/mjw/elfutils/commit/?h=translate_offs_symstrdata https://inbox.sourceware.org/elfutils-devel/20250622122147.1569555-1-m...@klomp.org/ -- You are receiving this mail because: You are on the CC list for the bug.