[PATCH 3/7 v3] doc: Add elf_next.3
Signed-off-by: Aaron Merey --- v3 changes: Use .B for EXAMPLES. On Fri, Jun 27, 2025 at 6:36 PM Mark Wielaard wrote: > > + /* 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 > > Should you check the cmd after the elf_next call? cmd is checked by elf_begin which terminates the loop when cmd is ELF_C_NULL. doc/Makefile.am | 1 + doc/elf_next.3 | 122 2 files changed, 123 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 ..4d8c16d2 --- /dev/null +++ b/doc/elf_next.3 @@ -0,0 +1,122 @@ +.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 +.B 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.50.0
[PATCH 6/7 v3] doc: Add elf_cntl.3
Signed-off-by: Aaron Merey --- v3: Clarify that future operations might fail after ELF_C_FDDONE unless ELF_C_FDREAD is used first. doc/Makefile.am | 1 + doc/elf_cntl.3 | 70 + 2 files changed, 71 insertions(+) create mode 100644 doc/elf_cntl.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index aae29ebc..486d9f22 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 ..58a3e5c7 --- /dev/null +++ b/doc/elf_cntl.3 @@ -0,0 +1,70 @@ +.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. Unless all data has been read from the file descriptor (see +.B ELF_C_FDREAD +below) future operation on the Elf descriptor may fail. + +.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. Using this command ensures that +.B ELF_C_FDDONE +may be used without causing future operations on the Elf descriptor to fail. + +.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.50.0
[PATCH 2/7] elf_getarhdr: Replace per-archive Elf_Arhdr storage with per-member storage
Currently each archive descriptor maintains a single Elf_Arhdr for the current archive member (as determined by elf_next or elf_rand) which is returned by elf_getarhdr. A single per-archive Elf_Arhdr is not ideal since elf_next and elf_rand can invalidate an archive member's reference to its own Elf_Arhdr. Avoid this possible invalidation by storing each Elf_Arhdr in its archive member descriptor. The existing Elf_Arhdr parsing and storage in the archive descriptor internal state is left mostly untouched. When an archive member is created with elf_begin it is given its own copy of its Elf_Arhdr from the archive descriptor. Also update tests/arextract.c with verification that each Elf_Arhdr is distinct and remains valid after calls to elf_next that would have previously invalidated the Elf_Arhdr. Signed-off-by: Aaron Merey --- libelf/elf_begin.c| 5 +++- libelf/elf_clone.c| 1 + libelf/elf_getarhdr.c | 22 ++ libelf/libelfP.h | 3 ++ tests/arextract.c | 68 ++- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index 3ed1f8d7..5ed5aaa3 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -1065,11 +1065,14 @@ dup_elf (int fildes, Elf_Cmd cmd, Elf *ref) result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr), ref->state.ar.elf_ar_hdr.ar_size, cmd, ref); - /* Enlist this new descriptor in the list of children. */ if (result != NULL) { + /* Enlist this new descriptor in the list of children. */ result->next = ref->state.ar.children; ref->state.ar.children = result; + + /* Ensure the member descriptor has its own copy of its header info. */ + result->elf_ar_hdr = ref->state.ar.elf_ar_hdr; } return result; diff --git a/libelf/elf_clone.c b/libelf/elf_clone.c index e6fe4729..d6c8d541 100644 --- a/libelf/elf_clone.c +++ b/libelf/elf_clone.c @@ -69,6 +69,7 @@ elf_clone (Elf *elf, Elf_Cmd cmd) == offsetof (struct Elf, state.elf64.scns)); retval->state.elf.scns_last = &retval->state.elf32.scns; retval->state.elf32.scns.max = elf->state.elf32.scns.max; + retval->elf_ar_hdr = elf->elf_ar_hdr; retval->class = elf->class; } diff --git a/libelf/elf_getarhdr.c b/libelf/elf_getarhdr.c index 509f1da5..ec85fa71 100644 --- a/libelf/elf_getarhdr.c +++ b/libelf/elf_getarhdr.c @@ -44,30 +44,12 @@ elf_getarhdr (Elf *elf) if (elf == NULL) return NULL; - Elf *parent = elf->parent; - /* Calling this function is not ok for any file type but archives. */ - if (parent == NULL) + if (elf->parent == NULL) { __libelf_seterrno (ELF_E_INVALID_OP); return NULL; } - /* Make sure we have read the archive header. */ - if (parent->state.ar.elf_ar_hdr.ar_name == NULL - && __libelf_next_arhdr_wrlock (parent) != 0) -{ - rwlock_wrlock (parent->lock); - int st = __libelf_next_arhdr_wrlock (parent); - rwlock_unlock (parent->lock); - - if (st != 0) - /* Something went wrong. Maybe there is no member left. */ - return NULL; -} - - /* We can be sure the parent is an archive. */ - assert (parent->kind == ELF_K_AR); - - return &parent->state.ar.elf_ar_hdr; + return &elf->elf_ar_hdr; } diff --git a/libelf/libelfP.h b/libelf/libelfP.h index 66e7e4dd..20120ad3 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -306,6 +306,9 @@ struct Elf /* Reference counting for the descriptor. */ int ref_count; + /* Per-descriptor copy of the structure returned by 'elf_getarhdr'. */ + Elf_Arhdr elf_ar_hdr; + /* Lock to handle multithreaded programs. */ rwlock_define (,lock); diff --git a/tests/arextract.c b/tests/arextract.c index 936d7f55..7920d1c9 100644 --- a/tests/arextract.c +++ b/tests/arextract.c @@ -21,12 +21,20 @@ #include #include +#include #include #include #include #include #include +typedef struct hdr_node { +Elf *elf; +Elf_Arhdr *hdr; +struct hdr_node *next; +} hdr_node; + +hdr_node *hdr_list = NULL; int main (int argc, char *argv[]) @@ -80,6 +88,27 @@ main (int argc, char *argv[]) exit (1); } +/* Keep a list of subelfs and their Elf_Arhdr. This is used to + verifiy that each archive member descriptor stores its own + Elf_Ahdr as opposed to the archive descriptor storing one + Elf_Ahdr at a time for all archive members. */ +hdr_node *node = calloc (1, sizeof (hdr_node)); +if (node == NULL) + { +printf ("calloc failed: %s\n", strerror (errno)); +exit (1); + } +node->elf = subelf; +node->hdr = arhdr; + +if (hdr_list != NULL) + { + node->next = hdr_list; +hdr_list = node; + } + else + hdr_list = node; + if (strcmp (arhdr->ar_name
[PATCH 5/7 v3] doc: Add elf_getarhdr.3
Signed-off-by: Aaron Merey --- v3: Remove mention of elf_rand and elf_next invalidating Elf_Arhdr. Change thread safety attribute to MT-safe. doc/Makefile.am| 1 + doc/elf_getarhdr.3 | 78 ++ 2 files changed, 79 insertions(+) create mode 100644 doc/elf_getarhdr.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index 6451ffab..aae29ebc 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -55,6 +55,7 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf_errmsg.3 \ elf_errno.3 \ elf_fill.3 \ + elf_getarhdr.3 \ elf_getaroff.3 \ elf_getbase.3 \ elf_getdata.3 \ diff --git a/doc/elf_getarhdr.3 b/doc/elf_getarhdr.3 new file mode 100644 index ..6ad90c69 --- /dev/null +++ b/doc/elf_getarhdr.3 @@ -0,0 +1,78 @@ +.TH ELF_GETARHDR 3 2025-06-06 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_getarhdr \- retrieve archive member header information + +.SH SYNOPSIS +.nf +.B #include + +.BI "Elf_Arhdr *elf_getarhdr(Elf *" elf ");" +.fi + +.SH DESCRIPTION +Return a +.B Elf_Arhdr * +describing the archive header of the archive member currently referred +to by an ELF descriptor. + +The +.B Elf_Arhdr +structure is defined as: + +.P +.nf +typedef struct { + char *ar_name;/* Name of archive member. */ + time_t ar_date; /* File date. */ + uid_t ar_uid; /* User ID. */ + gid_t ar_gid; /* Group ID. */ + mode_t ar_mode; /* File mode. */ + int64_t ar_size; /* File size. */ + char *ar_rawname; /* Original name of archive member. */ +} Elf_Arhdr; +.fi + +.SH PARAMETERS +.TP +.I elf +An ELF descriptor referring to a member of an archive file. + +.SH RETURN VALUE +If +.I elf +refers to an archive member, +.B elf_getarhdr() +returns a pointer to its archive header. +This pointer is valid until +.I elf +or the parent archive Elf descriptor are closed using +.BR elf_end() . +If +.I elf +does not refer to an archive member or the header cannot be +acquired then NULL is returned. + +.SH SEE ALSO +.BR elf_begin (3), +.BR elf_getaroff (3), +.BR elf_next (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_getarhdr () +T} Thread safety MT-safe +.TE + +.SH REPORTING BUGS +Report bugs to or https://sourceware.org/bugzilla/. -- 2.50.0
[PATCH 4/7 v3] doc: Add elf_getaroff.3
Signed-off-by: Aaron Merey --- v3 changes: Update return value description to reflect that elf_getaroff returns -1 if there's an error, not ELF_C_NULL (0). doc/Makefile.am| 1 + doc/elf_getaroff.3 | 58 ++ 2 files changed, 59 insertions(+) create mode 100644 doc/elf_getaroff.3 diff --git a/doc/Makefile.am b/doc/Makefile.am index fbfebfe0..6451ffab 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -55,6 +55,7 @@ notrans_dist_man3_MANS= elf32_checksum.3 \ elf_errmsg.3 \ elf_errno.3 \ elf_fill.3 \ + elf_getaroff.3 \ elf_getbase.3 \ elf_getdata.3 \ elf_getscn.3 \ diff --git a/doc/elf_getaroff.3 b/doc/elf_getaroff.3 new file mode 100644 index ..75f40795 --- /dev/null +++ b/doc/elf_getaroff.3 @@ -0,0 +1,58 @@ +.TH ELF_GETAROFF 3 2025-06-06 "Libelf" "Libelf Programmer's Manual" + +.SH NAME +elf_getaroff \- retrieve the offset of an archive member header + +.SH SYNOPSIS +.nf +.B #include + +.BI "int64_t elf_getaroff(Elf *" elf ");" +.fi +.SH DESCRIPTION +Return the file offset, in bytes, of the archive member header currently +referred to by an ELF descriptor. This is the offset of the member header +in the parent archive file. This offset can be used with +.BR elf_rand . + +.SH PARAMETERS +.TP +.I elf +Elf descriptor referring to a member of an archive file header. + +.SH RETURN VALUE +Return the file offset, in bytes, of the archive member header referred +to by +.IR elf . +If +.I elf +is NULL or is not a member of an archive, +return -1. + +.SH SEE ALSO +.BR elf_begin (3), +.BR elf_next (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_getaroff () +T} Thread safety MT-Safe +.TE + +.SH REPORTING BUGS +Report bugs to or https://sourceware.org/bugzilla/. + +.SH HISTORY +.B elf_getaroff +first appeared in elfutils 0.114. This elfutils libelf function may not be +found in other libelf implementations. -- 2.50.0
[PATCH 1/7] elf_getaroff: Fix elf_getaroff error return value
elf_getaroff currently returns ELF_C_NULL (0) to indicate that an error occured (ex. the Elf descriptor is not associated with an archive). However elf_getaroff is intended to return -1 if an error occurs. eu-ar assumes -1 indicates an error and other libelf implementations use -1 to indicate an error in elf_getaroff. Replace ELF_C_NULL with -1 as elf_getaroff's error return value. Signed-off-by: Aaron Merey --- libelf/elf_getaroff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libelf/elf_getaroff.c b/libelf/elf_getaroff.c index 5c102ad6..5737b350 100644 --- a/libelf/elf_getaroff.c +++ b/libelf/elf_getaroff.c @@ -43,7 +43,7 @@ elf_getaroff (Elf *elf) { /* Be gratious, the specs demand it. */ if (elf == NULL || elf->parent == NULL) -return ELF_C_NULL; +return -1; /* We can be sure the parent is an archive. */ Elf *parent = elf->parent; -- 2.50.0
[PATCH 7/7 v3] doc: Add elf_compress.3 and elf_compress_gnu.3
Signed-off-by: Aaron Merey --- v3: Use the libelf.h comment for elf_compress/elf_compress_gnu as the DESCRIPTION. Do not include ELFCOMPRESS_LOOS, ELFCOMPRESS_LOPROC, etc. as valid compression algorithm types. Mention that OS and arch-specific algorithm types aren't supported. doc/Makefile.am| 2 + doc/elf_compress.3 | 226 + doc/elf_compress_gnu.3 | 1 + 3 files changed, 229 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 486d9f22..9047a3ae 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 ..e1d584ad --- /dev/null +++ b/doc/elf_compress.3 @@ -0,0 +1,226 @@ +.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 +.PP +.B elf_compress +works by setting or clearing the +.B SHF_COMPRESS +flag from the section +.I Shdr +and will encode or decode a +.I Elf32_Chdr +or +.I Elf64_Chdr +at the start of the section data. +.B elf_compress_gnu +will encode or decode any section, but is traditionally only used for +sections that have a name starting with +.B ".debug" +when uncompressed or +.B ".zdebug" +when compressed and stores just the uncompressed size. +The GNU compression method is deprecated and should only be used for +legacy support. + +.B elf_compress +takes a compression type that should be either zero to decompress or an +.B ELFCOMPRESS +algorithm to use for compression. +Currently +.B ELFCOMPRESS_ZLIB +and +.B ELFCOMPRESS_ZSTD +are supported. +.B elf_compress_gnu +will compress in the traditional GNU compression format when +.I compress +is one and decompress the section data when +.I compress +is zero. + +The +.I FLAGS +argument can be zero or +.B ELF_CHF_FORCE. +If +.I FLAGS +contains +.B ELF_CHF_FORCE +then it will always compress the section, even if that would not reduce +the size of the data section (including the header). Otherwise +.B elf_compress +and +.B elf_compress_gnu +will compress the section only if the total data size is reduced. +.PP +On successful compression or decompression the function returns one. +If (not forced) compression is requested and the data section would not +actually reduce in size, the section is not actually compressed and zero +is returned. Otherwise +.B \-1 +is returned and +.B elf_errno +is set. +.PP +It is an error to request compression for a section that already has +.B SHF_COMPRESSED +set, or (for +.BR elf_compress ) +to request decompression for an section that doesn't have +.B SHF_COMPRESSED +set. +If a section has +.B SHF_COMPRESSED +set then calling +.B elf_compress_gnu +will result in an error. +The section has to be decompressed first using +.B elf_compress. +Calling +.B elf_compress +on a section compressed with +.B elf_compress_gnu +is fine, but probably useless. +.PP +It is always an error to call these functions on +.B SHT_NOBITS +sections or if the section has the +.B SHF_ALLOC +flag set. +.B elf_compress_gnu +will not check whether the section name starts with +.B ".debug" +or +.B ".zdebug". +It is the responsibility of the caller to make sure the deprecated GNU +compression method is only called on correctly named sections (and to +change the name of the section when using +.BR elf_compress_gnu ). +.PP +All previous returned +.I Shdr +and +.I Elf_Data +buffers are invalidated by this call and should no longer be accessed. +.PP +Note that although this changes the header and data returned it doesn't +mark the section as dirty. To keep the changes when calling +.B elf_update +the section has to be flagged +.B ELF_F_DIRTY. + +.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. Elfutils +libelf does not support OS and processor specific compression algorithms. +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 Z