[3/7,v3] doc: Add elf_next.3

Message ID 20250715042557.708628-3-amerey@redhat.com
State Superseded
Delegated to: Mark Wielaard
Headers
Series [1/7] elf_getaroff: Fix elf_getaroff error return value |

Commit Message

Aaron Merey July 15, 2025, 4:25 a.m. UTC
  Signed-off-by: Aaron Merey <amerey@redhat.com>

---
v3 changes: Use .B for EXAMPLES.

On Fri, Jun 27, 2025 at 6:36 PM Mark Wielaard <mark@klomp.org> 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
  

Comments

Mark Wielaard July 17, 2025, 2:30 p.m. UTC | #1
Hi Aaron,

On Tue, 2025-07-15 at 00:25 -0400, Aaron Merey wrote:
> Signed-off-by: Aaron Merey <amerey@redhat.com>
> 
> ---
> v3 changes: Use .B for EXAMPLES.
> 
> On Fri, Jun 27, 2025 at 6:36 PM Mark Wielaard <mark@klomp.org> 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.

Aha, a little subtle, so if subelf was the last member of elf then
elf_next returns ELF_C_NULL and elf_begin with ELF_C_NULL always
returns 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

OK.

> diff --git a/doc/elf_next.3 b/doc/elf_next.3
> new file mode 100644
> index 00000000..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 <libelf.h>
> +
> +.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).

I think the text is correct, but I find it hard to follow. I am not
sure someone who doesn't already know how elf_begin and elf_next
interact will after reading this. Happy to see the example though.

> +.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.

This description is a little more clear.

> +.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);
> +        }
> +    }

Maybe change the "Get next archive element" to say something like
"Prepare elf ar archive and get cmd for elf_begin to get next archive
element, or ELF_C_NULL if there are no more."?

At least I was clearly a little confused, dunno if extra text makes
people less confused.

> +  elf_end (elf);
> +  close (fd);
> +.fi

I do like the example because it is complete.

> +.SH SEE ALSO
> +.BR elf_begin (3),
> +.BR elf_rand (3),
> +.BR libelf (3),
> +.BR elf (5)

OK.

> +.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

Yes, but it does race setting the state on the archive elf with
elf_rand or another elf_next. Dunno if you can/should express that
here.

> +.SH REPORTING BUGS
> +Report bugs to <elfutils-devel@sourceware.org> or https://sourceware.org/bugzilla/.

Thanks,

Mark
  

Patch

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 00000000..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 <libelf.h>
+
+.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 <elfutils-devel@sourceware.org> or https://sourceware.org/bugzilla/.