libctf: eliminate dtd_u, part 4: enums
authorNick Alcock <nick.alcock@oracle.com>
Thu, 18 Mar 2021 12:37:52 +0000 (12:37 +0000)
committerNick Alcock <nick.alcock@oracle.com>
Thu, 18 Mar 2021 12:40:40 +0000 (12:40 +0000)
This is the first tricky one, the first complex multi-entry vlen
containing strings.  To handle this in vlen form, we have to handle
pending refs moving around on realloc.

We grow vlen regions using a new ctf_grow_vlen function, and iterate
through the existing enums every time a grow happens, telling the string
machinery the distance between the old and new vlen region and letting
it adjust the pending refs accordingly.  (This avoids traversing all
outstanding refs to find the refs that need adjusting, at the cost of
having to traverse one enum: an obvious major performance win.)

Addition of enums themselves (and also structs/unions later) is a bit
trickier than earlier forms, because the type might be being promoted
from a forward, and forwards have no vlen: so we have to spot that and
create it if needed.

Serialization of enums simplifies down to just telling the string
machinery about the string refs; all the enum type-lookup code loses all
its dynamic member lookup complexity entirely.

A new test is added that iterates over (and gets values of) an enum with
enough members to force a round of vlen growth.

libctf/ChangeLog
2021-03-18  Nick Alcock  <nick.alcock@oracle.com>

* ctf-impl.h (ctf_dtdef_t) <dtd_vlen_alloc>: New.
(ctf_str_move_pending): Declare.
* ctf-string.c (ctf_str_add_ref_internal): Fix error return.
(ctf_str_move_pending): New.
* ctf-create.c (ctf_grow_vlen): New.
(ctf_dtd_delete): Zero out the vlen_alloc after free.  Free the
vlen later: iterate over it and free enum name refs first.
(ctf_add_generic): Populate dtd_vlen_alloc from vlen.
(ctf_add_enum): populate the vlen; do it by hand if promoting
forwards.
(ctf_add_enumerator): Set up the vlen rather than the dmd.  Expand
it as needed, repointing string refs via ctf_str_move_pending. Add
the enumerand names as pending strings.
* ctf-serialize.c (ctf_copy_emembers): Remove.
(ctf_emit_type_sect): Copy the vlen into place and ref the
strings.
* ctf-types.c (ctf_enum_next): The dynamic portion now uses
the same code as the non-dynamic.
(ctf_enum_name): Likewise.
(ctf_enum_value): Likewise.
* testsuite/libctf-lookup/enum-many-ctf.c: New test.
* testsuite/libctf-lookup/enum-many.lk: New test.

libctf/ChangeLog
libctf/ctf-create.c
libctf/ctf-impl.h
libctf/ctf-serialize.c
libctf/ctf-string.c
libctf/ctf-types.c
libctf/testsuite/libctf-lookup/enum-many-ctf.c [new file with mode: 0644]
libctf/testsuite/libctf-lookup/enum-many.lk [new file with mode: 0644]

index b4da0407ca9736263ff0a269efb424fe33b31f4a..fa333d5c2bda49a9816cf66c49354771b0e4afe7 100644 (file)
@@ -1,3 +1,28 @@
+2021-03-18  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-impl.h (ctf_dtdef_t) <dtd_vlen_alloc>: New.
+       (ctf_str_move_pending): Declare.
+       * ctf-string.c (ctf_str_add_ref_internal): Fix error return.
+       (ctf_str_move_pending): New.
+       * ctf-create.c (ctf_grow_vlen): New.
+       (ctf_dtd_delete): Zero out the vlen_alloc after free.  Free the
+       vlen later: iterate over it and free enum name refs first.
+       (ctf_add_generic): Populate dtd_vlen_alloc from vlen.
+       (ctf_add_enum): populate the vlen; do it by hand if promoting
+       forwards.
+       (ctf_add_enumerator): Set up the vlen rather than the dmd.  Expand
+       it as needed, repointing string refs via ctf_str_move_pending. Add
+       the enumerand names as pending strings.
+       * ctf-serialize.c (ctf_copy_emembers): Remove.
+       (ctf_emit_type_sect): Copy the vlen into place and ref the
+       strings.
+       * ctf-types.c (ctf_enum_next): The dynamic portion now uses
+       the same code as the non-dynamic.
+       (ctf_enum_name): Likewise.
+       (ctf_enum_value): Likewise.
+       * testsuite/libctf-lookup/enum-many-ctf.c: New test.
+       * testsuite/libctf-lookup/enum-many.lk: New test.
+
 2021-03-18  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-hash.c (ctf_dynset_elements): New.
index ea2c1481b6c7e37ab104efe43e1ab45c50d1b178..3218e3e31eac3503bad840e5407fa3640e639a5f 100644 (file)
@@ -64,6 +64,30 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
   return 0;
 }
 
+/* Make sure a vlen has enough space: expand it otherwise.  Unlike the ptrtab,
+   which grows quite slowly, the vlen grows in big jumps because it is quite
+   expensive to expand: the caller has to scan the old vlen for string refs
+   first and remove them, then re-add them afterwards.  The initial size is
+   more or less arbitrary.  */
+static int
+ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
+{
+  unsigned char *old = dtd->dtd_vlen;
+
+  if (dtd->dtd_vlen_alloc > vlen)
+    return 0;
+
+  if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen,
+                               dtd->dtd_vlen_alloc * 2)) == NULL)
+    {
+      dtd->dtd_vlen = old;
+      return (ctf_set_errno (fp, ENOMEM));
+    }
+  memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
+  dtd->dtd_vlen_alloc *= 2;
+  return 0;
+}
+
 /* To create an empty CTF dict, we just declare a zeroed header and call
    ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new dict r/w and
    initialize the dynamic members.  We start assigning type IDs at 1 because
@@ -222,17 +246,16 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
 {
   ctf_dmdef_t *dmd, *nmd;
   int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+  size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
   int name_kind = kind;
   const char *name;
 
   ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
-  free (dtd->dtd_vlen);
 
   switch (kind)
     {
     case CTF_K_STRUCT:
     case CTF_K_UNION:
-    case CTF_K_ENUM:
       for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
           dmd != NULL; dmd = nmd)
        {
@@ -242,10 +265,22 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
          free (dmd);
        }
       break;
+    case CTF_K_ENUM:
+      {
+       ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+       size_t i;
+
+       for (i = 0; i < vlen; i++)
+         ctf_str_remove_ref (fp, ctf_strraw (fp, en[i].cte_name),
+                             &en[i].cte_name);
+      }
+      break;
     case CTF_K_FORWARD:
       name_kind = dtd->dtd_data.ctt_type;
       break;
     }
+  free (dtd->dtd_vlen);
+  dtd->dtd_vlen_alloc = 0;
 
   if (dtd->dtd_data.ctt_name
       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL
@@ -402,6 +437,9 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   return 0;
 }
 
+/* Note: vlen is the amount of space *allocated* for the vlen.  It may well not
+   be the amount of space used (yet): the space used is declared in per-kind
+   fashion in the dtd_data's info word.  */
 static ctf_id_t
 ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
                 size_t vlen, ctf_dtdef_t **rp)
@@ -428,6 +466,7 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
 
+  dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
     {
       if ((dtd->dtd_vlen = calloc (1, vlen)) == NULL)
@@ -831,6 +870,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
+  size_t initial_vlen = sizeof (ctf_enum_t) * 16;
 
   /* Promote root-visible forwards to enums.  */
   if (name != NULL)
@@ -839,9 +879,17 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM,
-                                   0, &dtd)) == CTF_ERR)
+                                   initial_vlen, &dtd)) == CTF_ERR)
     return CTF_ERR;            /* errno is set for us.  */
 
+  /* Forwards won't have any vlen yet.  */
+  if (dtd->dtd_vlen_alloc == 0)
+    {
+      if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
+       return (ctf_set_errno (fp, ENOMEM));
+      dtd->dtd_vlen_alloc = initial_vlen;
+    }
+
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
   dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
 
@@ -956,10 +1004,11 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
                    int value)
 {
   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
-  ctf_dmdef_t *dmd;
+  unsigned char *old_vlen;
+  ctf_enum_t *en;
+  size_t i;
 
   uint32_t kind, vlen, root;
-  char *s;
 
   if (name == NULL)
     return (ctf_set_errno (fp, EINVAL));
@@ -980,29 +1029,32 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   if (vlen == CTF_MAX_VLEN)
     return (ctf_set_errno (fp, ECTF_DTFULL));
 
-  for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-       dmd != NULL; dmd = ctf_list_next (dmd))
+  old_vlen = dtd->dtd_vlen;
+  if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
+    return -1;                                 /* errno is set for us.  */
+  en = (ctf_enum_t *) dtd->dtd_vlen;
+
+  if (dtd->dtd_vlen != old_vlen)
     {
-      if (strcmp (dmd->dmd_name, name) == 0)
-       return (ctf_set_errno (fp, ECTF_DUPLICATE));
-    }
+      ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen;
 
-  if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+      /* Remove pending refs in the old vlen region and reapply them.  */
 
-  if ((s = strdup (name)) == NULL)
-    {
-      free (dmd);
-      return (ctf_set_errno (fp, EAGAIN));
+      for (i = 0; i < vlen; i++)
+       ctf_str_move_pending (fp, &en[i].cte_name, move);
     }
 
-  dmd->dmd_name = s;
-  dmd->dmd_type = CTF_ERR;
-  dmd->dmd_offset = 0;
-  dmd->dmd_value = value;
+  for (i = 0; i < vlen; i++)
+    if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+
+  en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
+  en[i].cte_value = value;
+
+  if (en[i].cte_name == 0 && name != NULL && name[0] != '\0')
+    return -1;                                 /* errno is set for us. */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
-  ctf_list_append (&dtd->dtd_u.dtu_members, dmd);
 
   fp->ctf_flags |= LCTF_DIRTY;
 
index a319d7f74a21916e40ae45bcdf23b4097c301137..9a82d953ae808b76936147e22f376924272016ef 100644 (file)
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <limits.h>
@@ -192,6 +193,7 @@ typedef struct ctf_dtdef
   ctf_list_t dtd_list;         /* List forward/back pointers.  */
   ctf_id_t dtd_type;           /* Type identifier for this definition.  */
   ctf_type_t dtd_data;         /* Type node, including name.  */
+  size_t dtd_vlen_alloc;       /* Total vlen space allocated.  */
   unsigned char *dtd_vlen;     /* Variable-length data for this type.  */
   union
   {
@@ -734,6 +736,7 @@ extern void ctf_str_free_atoms (ctf_dict_t *);
 extern uint32_t ctf_str_add (ctf_dict_t *, const char *);
 extern uint32_t ctf_str_add_ref (ctf_dict_t *, const char *, uint32_t *ref);
 extern uint32_t ctf_str_add_pending (ctf_dict_t *, const char *, uint32_t *);
+extern int ctf_str_move_pending (ctf_dict_t *, uint32_t *, ptrdiff_t);
 extern int ctf_str_add_external (ctf_dict_t *, const char *, uint32_t offset);
 extern void ctf_str_remove_ref (ctf_dict_t *, const char *, uint32_t *ref);
 extern void ctf_str_rollback (ctf_dict_t *, ctf_snapshot_id_t);
index 0eff0e197fa248ecfaecf64861ce31b512f24d1d..5d94f44b0d02449bffe6ee24436c7f025e2cb937 100644 (file)
@@ -770,26 +770,6 @@ ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
   return t;
 }
 
-static unsigned char *
-ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
-  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-  ctf_enum_t cte;
-
-  for (; dmd != NULL; dmd = ctf_list_next (dmd))
-    {
-      ctf_enum_t *copied;
-
-      cte.cte_value = dmd->dmd_value;
-      memcpy (t, &cte, sizeof (cte));
-      copied = (ctf_enum_t *) t;
-      ctf_str_add_ref (fp, dmd->dmd_name, &copied->cte_name);
-      t += sizeof (cte);
-    }
-
-  return t;
-}
-
 /* Iterate through the dynamic type definition list and compute the
    size of the CTF type section.  */
 
@@ -860,6 +840,7 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
       size_t len;
       ctf_stype_t *copied;
       const char *name;
+      size_t i;
 
       if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
        len = sizeof (ctf_stype_t);
@@ -908,8 +889,22 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
          break;
 
        case CTF_K_ENUM:
-         t = ctf_copy_emembers (fp, dtd, t);
-         break;
+         {
+           ctf_enum_t *dtd_vlen = (struct ctf_enum *) dtd->dtd_vlen;
+           ctf_enum_t *t_vlen = (struct ctf_enum *) t;
+
+           memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_enum) * vlen);
+           for (i = 0; i < vlen; i++)
+             {
+               const char *name = ctf_strraw (fp, dtd_vlen[i].cte_name);
+
+               ctf_str_add_ref (fp, name, &t_vlen[i].cte_name);
+               ctf_str_add_ref (fp, name, &dtd_vlen[i].cte_name);
+             }
+           t += sizeof (struct ctf_enum) * vlen;
+
+           break;
+         }
        }
     }
 
index 9f0e5400141a5cdc68dc0959782a082bf35cfac3..2e98484f2090f64259694a0fe07f4890217fe6a6 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <ctf-impl.h>
 #include <string.h>
+#include <assert.h>
 
 /* Convert an encoded CTF string name into a pointer to a C string, using an
   explicit internal strtab rather than the fp-based one.  */
@@ -228,6 +229,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
   free (atom);
   free (aref);
   free (newstr);
+  ctf_set_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -288,6 +290,21 @@ ctf_str_add_pending (ctf_dict_t *fp, const char *str, uint32_t *ref)
   return atom->csa_offset;
 }
 
+/* Note that a pending ref now located at NEW_REF has moved by BYTES bytes.  */
+int
+ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
+{
+  if (bytes == 0)
+    return 0;
+
+  if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
+    return (ctf_set_errno (fp, ENOMEM));
+
+  ctf_dynset_remove (fp->ctf_str_pending_ref,
+                    (void *) ((signed char *) new_ref - bytes));
+  return 0;
+}
+
 /* Add an external strtab reference at OFFSET.  Returns zero if the addition
    failed, nonzero otherwise.  */
 int
index 1e1ce8ee5290ea3b658b9ca3612d4e005b058905..49264ebf5ab2f9d994902596b188ec3ef6a82092 100644 (file)
@@ -318,22 +318,13 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       dtd = ctf_dynamic_type (fp, type);
       i->ctn_iter_fun = (void (*) (void)) ctf_enum_next;
-
-      /* We depend below on the RDWR state indicating whether the DTD-related
-        fields or the DMD-related fields have been initialized.  */
-
-      assert ((dtd && (fp->ctf_flags & LCTF_RDWR))
-             || (!dtd && (!(fp->ctf_flags & LCTF_RDWR))));
+      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
 
       if (dtd == NULL)
-       {
-         i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-
-         i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
-                                             i->ctn_increment);
-       }
+       i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
+                                           i->ctn_increment);
       else
-       i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+       i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
 
       *it = i;
     }
@@ -357,27 +348,14 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       return NULL;
     }
 
-  if (!(fp->ctf_flags & LCTF_RDWR))
-    {
-      if (i->ctn_n == 0)
-       goto end_iter;
-
-      name = ctf_strptr (fp, i->u.ctn_en->cte_name);
-      if (val)
-       *val = i->u.ctn_en->cte_value;
-      i->u.ctn_en++;
-      i->ctn_n--;
-    }
-  else
-    {
-      if (i->u.ctn_dmd == NULL)
-       goto end_iter;
+  if (i->ctn_n == 0)
+    goto end_iter;
 
-      name = i->u.ctn_dmd->dmd_name;
-      if (val)
-       *val = i->u.ctn_dmd->dmd_value;
-      i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
-    }
+  name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+  if (val)
+    *val = i->u.ctn_en->cte_value;
+  i->u.ctn_en++;
+  i->ctn_n--;
 
   return name;
 
@@ -1554,35 +1532,24 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      ctf_set_errno (ofp, ECTF_NOTENUM);
       return NULL;
     }
 
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+  ctf_get_ctt_size (fp, tp, NULL, &increment);
 
   if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    {
-      ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
-
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
-       {
-         if (ep->cte_value == value)
-           return (ctf_strptr (fp, ep->cte_name));
-       }
-    }
+    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
   else
-    {
-      ctf_dmdef_t *dmd;
+    ep = (const ctf_enum_t *) dtd->dtd_vlen;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-          dmd != NULL; dmd = ctf_list_next (dmd))
-       {
-         if (dmd->dmd_value == value)
-           return dmd->dmd_name;
-       }
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (ep->cte_value == value)
+       return (ctf_strptr (fp, ep->cte_name));
     }
 
-  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno (ofp, ECTF_NOENUMNAM);
   return NULL;
 }
 
@@ -1590,7 +1557,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
    matching name can be found.  Otherwise CTF_ERR is returned.  */
 
 int
-ctf_enum_value (ctf_dict_t * fp, ctf_id_t type, const char *name, int *valp)
+ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 {
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
@@ -1611,39 +1578,24 @@ ctf_enum_value (ctf_dict_t * fp, ctf_id_t type, const char *name, int *valp)
       return -1;
     }
 
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
-
-  ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
+  ctf_get_ctt_size (fp, tp, NULL, &increment);
 
   if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    {
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
-       {
-         if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
-           {
-             if (valp != NULL)
-               *valp = ep->cte_value;
-             return 0;
-           }
-       }
-    }
+    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
   else
-    {
-      ctf_dmdef_t *dmd;
+    ep = (const ctf_enum_t *) dtd->dtd_vlen;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-          dmd != NULL; dmd = ctf_list_next (dmd))
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
        {
-         if (strcmp (dmd->dmd_name, name) == 0)
-           {
-             if (valp != NULL)
-               *valp = dmd->dmd_value;
-             return 0;
-           }
+         if (valp != NULL)
+           *valp = ep->cte_value;
+         return 0;
        }
     }
 
-  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno (ofp, ECTF_NOENUMNAM);
   return -1;
 }
 
diff --git a/libctf/testsuite/libctf-lookup/enum-many-ctf.c b/libctf/testsuite/libctf-lookup/enum-many-ctf.c
new file mode 100644 (file)
index 0000000..f2297d7
--- /dev/null
@@ -0,0 +1,10 @@
+/* Looked up item by item. */
+enum e { ENUMSAMPLE_1 = 0, ENUMSAMPLE_2 = 1 };
+
+/* Looked up via both sorts of iterator in turn.  */
+enum ie { IE_0 = -10, IE_1, IE_2, IE_3, IE_4, IE_5, IE_6, IE_7, IE_8, IE_9, IE_A, IE_B, IE_C, IE_D, IE_E, IE_F,
+         IE_10, IE_11, IE_12, IE_13, IE_14, IE_15, IE_16, IE_17, IE_18, IE_19, IE_1A, IE_1B, IE_1C, IE_1D, IE_1E, IE_1F,
+         IE_20, IE_21, IE_22, IE_23, IE_24, IE_25, IE_26, IE_27, IE_28, IE_29, IE_2A, IE_2B, IE_2C, IE_2D, IE_2E, IE_2F};
+
+enum e foo;
+enum ie bar;
diff --git a/libctf/testsuite/libctf-lookup/enum-many.lk b/libctf/testsuite/libctf-lookup/enum-many.lk
new file mode 100644 (file)
index 0000000..17eca66
--- /dev/null
@@ -0,0 +1,101 @@
+# source: enum-many-ctf.c
+# lookup: enum.c
+# link: on
+Enum e enumerand ENUMSAMPLE_1 has value 0
+Enum e enumerand ENUMSAMPLE_2 has value 1
+iter test: IE_0 has value -10
+iter test: IE_1 has value -9
+iter test: IE_2 has value -8
+iter test: IE_3 has value -7
+iter test: IE_4 has value -6
+iter test: IE_5 has value -5
+iter test: IE_6 has value -4
+iter test: IE_7 has value -3
+iter test: IE_8 has value -2
+iter test: IE_9 has value -1
+iter test: IE_A has value 0
+iter test: IE_B has value 1
+iter test: IE_C has value 2
+iter test: IE_D has value 3
+iter test: IE_E has value 4
+iter test: IE_F has value 5
+iter test: IE_10 has value 6
+iter test: IE_11 has value 7
+iter test: IE_12 has value 8
+iter test: IE_13 has value 9
+iter test: IE_14 has value 10
+iter test: IE_15 has value 11
+iter test: IE_16 has value 12
+iter test: IE_17 has value 13
+iter test: IE_18 has value 14
+iter test: IE_19 has value 15
+iter test: IE_1A has value 16
+iter test: IE_1B has value 17
+iter test: IE_1C has value 18
+iter test: IE_1D has value 19
+iter test: IE_1E has value 20
+iter test: IE_1F has value 21
+iter test: IE_20 has value 22
+iter test: IE_21 has value 23
+iter test: IE_22 has value 24
+iter test: IE_23 has value 25
+iter test: IE_24 has value 26
+iter test: IE_25 has value 27
+iter test: IE_26 has value 28
+iter test: IE_27 has value 29
+iter test: IE_28 has value 30
+iter test: IE_29 has value 31
+iter test: IE_2A has value 32
+iter test: IE_2B has value 33
+iter test: IE_2C has value 34
+iter test: IE_2D has value 35
+iter test: IE_2E has value 36
+iter test: IE_2F has value 37
+next test: IE_0 has value -10
+next test: IE_1 has value -9
+next test: IE_2 has value -8
+next test: IE_3 has value -7
+next test: IE_4 has value -6
+next test: IE_5 has value -5
+next test: IE_6 has value -4
+next test: IE_7 has value -3
+next test: IE_8 has value -2
+next test: IE_9 has value -1
+next test: IE_A has value 0
+next test: IE_B has value 1
+next test: IE_C has value 2
+next test: IE_D has value 3
+next test: IE_E has value 4
+next test: IE_F has value 5
+next test: IE_10 has value 6
+next test: IE_11 has value 7
+next test: IE_12 has value 8
+next test: IE_13 has value 9
+next test: IE_14 has value 10
+next test: IE_15 has value 11
+next test: IE_16 has value 12
+next test: IE_17 has value 13
+next test: IE_18 has value 14
+next test: IE_19 has value 15
+next test: IE_1A has value 16
+next test: IE_1B has value 17
+next test: IE_1C has value 18
+next test: IE_1D has value 19
+next test: IE_1E has value 20
+next test: IE_1F has value 21
+next test: IE_20 has value 22
+next test: IE_21 has value 23
+next test: IE_22 has value 24
+next test: IE_23 has value 25
+next test: IE_24 has value 26
+next test: IE_25 has value 27
+next test: IE_26 has value 28
+next test: IE_27 has value 29
+next test: IE_28 has value 30
+next test: IE_29 has value 31
+next test: IE_2A has value 32
+next test: IE_2B has value 33
+next test: IE_2C has value 34
+next test: IE_2D has value 35
+next test: IE_2E has value 36
+next test: IE_2F has value 37