libctf: installable libctf as a shared library
[deliverable/binutils-gdb.git] / libctf / ctf-create.c
index 24ea114f294426b08273adc43065dfff5d22702d..8eb16738a11844cb15b98ae22e44895d526465bb 100644 (file)
@@ -170,31 +170,37 @@ ctf_copy_emembers (ctf_file_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
 
 /* Sort a newly-constructed static variable array.  */
 
+typedef struct ctf_sort_var_arg_cb
+{
+  ctf_file_t *fp;
+  ctf_strs_t *strtab;
+} ctf_sort_var_arg_cb_t;
+
 static int
-ctf_sort_var (const void *one_, const void *two_, void *strtab_)
+ctf_sort_var (const void *one_, const void *two_, void *arg_)
 {
   const ctf_varent_t *one = one_;
   const ctf_varent_t *two = two_;
-  const char *strtab = strtab_;
-  const char *n1 = strtab + CTF_NAME_OFFSET (one->ctv_name);
-  const char *n2 = strtab + CTF_NAME_OFFSET (two->ctv_name);
+  ctf_sort_var_arg_cb_t *arg = arg_;
 
-  return (strcmp (n1, n2));
+  return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
+                 ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
 }
 
 /* If the specified CTF container is writable and has been modified, reload this
    container with the updated type definitions.  In order to make this code and
    the rest of libctf as simple as possible, we perform updates by taking the
    dynamic type definitions and creating an in-memory CTF file containing the
-   definitions, and then call ctf_simple_open() on it.  This not only leverages
-   ctf_simple_open(), but also avoids having to bifurcate the rest of the library
-   code with different lookup paths for static and dynamic type definitions.  We
-   are therefore optimizing greatly for lookup over update, which we assume will
-   be an uncommon operation.  We perform one extra trick here for the benefit of
-   callers and to keep our code simple: ctf_simple_open() will return a new
-   ctf_file_t, but we want to keep the fp constant for the caller, so after
-   ctf_simple_open() returns, we use memcpy to swap the interior of the old and
-   new ctf_file_t's, and then free the old.  */
+   definitions, and then call ctf_simple_open_internal() on it.  This not only
+   leverages ctf_simple_open(), but also avoids having to bifurcate the rest of
+   the library code with different lookup paths for static and dynamic type
+   definitions.  We are therefore optimizing greatly for lookup over update,
+   which we assume will be an uncommon operation.  We perform one extra trick
+   here for the benefit of callers and to keep our code simple:
+   ctf_simple_open_internal() will return a new ctf_file_t, but we want to keep
+   the fp constant for the caller, so after ctf_simple_open_internal() returns,
+   we use memcpy to swap the interior of the old and new ctf_file_t's, and then
+   free the old.  */
 int
 ctf_update (ctf_file_t *fp)
 {
@@ -294,6 +300,8 @@ ctf_update (ctf_file_t *fp)
   hdrp = (ctf_header_t *) buf;
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
     ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
+  if (fp->ctf_cuname != NULL)
+    ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
 
   /* Work over the variable list, translating everything into ctf_varent_t's and
      prepping the string table.  */
@@ -410,10 +418,17 @@ ctf_update (ctf_file_t *fp)
   strtab = ctf_str_write_strtab (fp);
   ctf_str_purge_refs (fp);
 
+  if (strtab.cts_strs == NULL)
+    {
+      ctf_free (buf);
+      return (ctf_set_errno (fp, EAGAIN));
+    }
+
   /* Now the string table is constructed, we can sort the buffer of
      ctf_varent_t's.  */
+  ctf_sort_var_arg_cb_t sort_var_arg = { fp, (ctf_strs_t *) &strtab };
   ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var,
-              strtab.cts_strs);
+              &sort_var_arg);
 
   if ((newbuf = ctf_realloc (fp, buf, buf_size + strtab.cts_len)) == NULL)
     {
@@ -431,8 +446,9 @@ ctf_update (ctf_file_t *fp)
   /* Finally, we are ready to ctf_simple_open() the new container.  If this
      is successful, we then switch nfp and fp and free the old container.  */
 
-  if ((nfp = ctf_simple_open ((char *) buf, buf_size, NULL, 0, 0, NULL,
-                             0, &err)) == NULL)
+  if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0,
+                                      0, NULL, 0, fp->ctf_syn_ext_strtab,
+                                      &err)) == NULL)
     {
       ctf_free (buf);
       return (ctf_set_errno (fp, err));
@@ -443,7 +459,8 @@ ctf_update (ctf_file_t *fp)
 
   nfp->ctf_refcnt = fp->ctf_refcnt;
   nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
-  nfp->ctf_data.cts_data = NULL;       /* Force ctf_free() on close.  */
+  if (nfp->ctf_dynbase == NULL)
+    nfp->ctf_dynbase = buf;            /* Make sure buf is freed on close.  */
   nfp->ctf_dthash = fp->ctf_dthash;
   nfp->ctf_dtdefs = fp->ctf_dtdefs;
   nfp->ctf_dtbyname = fp->ctf_dtbyname;
@@ -453,6 +470,13 @@ ctf_update (ctf_file_t *fp)
   nfp->ctf_dtoldid = fp->ctf_dtnextid - 1;
   nfp->ctf_snapshots = fp->ctf_snapshots + 1;
   nfp->ctf_specific = fp->ctf_specific;
+  nfp->ctf_link_inputs = fp->ctf_link_inputs;
+  nfp->ctf_link_outputs = fp->ctf_link_outputs;
+  nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
+  nfp->ctf_link_cu_mapping = fp->ctf_link_cu_mapping;
+  nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping;
+  nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer;
+  nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg;
 
   nfp->ctf_snapshot_lu = fp->ctf_snapshots;
 
@@ -462,6 +486,11 @@ ctf_update (ctf_file_t *fp)
   nfp->ctf_str_atoms = fp->ctf_str_atoms;
   fp->ctf_str_atoms = NULL;
   memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t));
+  fp->ctf_link_inputs = NULL;
+  fp->ctf_link_outputs = NULL;
+  fp->ctf_syn_ext_strtab = NULL;
+  fp->ctf_link_cu_mapping = NULL;
+  fp->ctf_link_type_mapping = NULL;
 
   fp->ctf_dvhash = NULL;
   memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
@@ -1523,7 +1552,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
   ctf_id_t tmp;
 
   const char *name;
-  uint32_t kind, flag, vlen;
+  uint32_t kind, forward_kind, flag, vlen;
 
   const ctf_type_t *src_tp, *dst_tp;
   ctf_bundle_t src, dst;
@@ -1534,6 +1563,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
   ctf_funcinfo_t ctc;
 
   ctf_hash_t *hp;
+  ctf_id_t orig_src_type = src_type;
 
   if (!(dst_fp->ctf_flags & LCTF_RDWR))
     return (ctf_set_errno (dst_fp, ECTF_RDONLY));
@@ -1546,7 +1576,11 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
   flag = LCTF_INFO_ISROOT (src_fp, src_tp->ctt_info);
   vlen = LCTF_INFO_VLEN (src_fp, src_tp->ctt_info);
 
-  switch (kind)
+  forward_kind = kind;
+  if (kind == CTF_K_FORWARD)
+    forward_kind = src_tp->ctt_type;
+
+  switch (forward_kind)
     {
     case CTF_K_STRUCT:
       hp = dst_fp->ctf_structs;
@@ -1575,16 +1609,30 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
 
   /* If an identically named dst_type exists, fail with ECTF_CONFLICT
      unless dst_type is a forward declaration and src_type is a struct,
-     union, or enum (i.e. the definition of the previous forward decl).  */
+     union, or enum (i.e. the definition of the previous forward decl).
 
-  if (dst_type != CTF_ERR && dst_kind != kind
-      && (dst_kind != CTF_K_FORWARD
-         || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
-             && kind != CTF_K_UNION)))
+     We also allow addition in the opposite order (addition of a forward when a
+     struct, union, or enum already exists), which is a NOP and returns the
+     already-present struct, union, or enum.  */
+
+  if (dst_type != CTF_ERR && dst_kind != kind)
     {
-      ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
-                  "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
-      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+      if (kind == CTF_K_FORWARD
+         && (dst_kind == CTF_K_ENUM || dst_kind == CTF_K_STRUCT
+             || dst_kind == CTF_K_UNION))
+       {
+         ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
+         return dst_type;
+       }
+
+      if (dst_kind != CTF_K_FORWARD
+         || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
+             && kind != CTF_K_UNION))
+       {
+         ctf_dprintf ("Conflict for type %s: kinds differ, new: %i; "
+                      "old (ID %lx): %i\n", name, kind, dst_type, dst_kind);
+         return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
+       }
     }
 
   /* We take special action for an integer, float, or slice since it is
@@ -1617,7 +1665,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
              if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
                {
                  if (kind != CTF_K_SLICE)
-                   return dst_type;
+                   {
+                     ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
+                     return dst_type;
+                   }
                }
              else
                  {
@@ -1656,7 +1707,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
              int match;        /* Do the encodings match?  */
 
              if (kind != CTF_K_INTEGER && kind != CTF_K_FLOAT && kind != CTF_K_SLICE)
-               return dtd->dtd_type;
+               {
+                 ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type);
+                 return dtd->dtd_type;
+               }
 
              sroot = (flag & CTF_ADD_ROOT);
              droot = (LCTF_INFO_ISROOT (dst_fp,
@@ -1675,7 +1729,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
              if (match && sroot == droot)
                {
                  if (kind != CTF_K_SLICE)
-                   return dtd->dtd_type;
+                   {
+                     ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type);
+                     return dtd->dtd_type;
+                   }
                }
              else if (!match && sroot && droot)
                {
@@ -1885,10 +1942,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
 
     case CTF_K_FORWARD:
       if (dst_type == CTF_ERR)
-       {
-         dst_type = ctf_add_forward (dst_fp, flag,
-                                     name, CTF_K_STRUCT); /* Assume STRUCT. */
-       }
+         dst_type = ctf_add_forward (dst_fp, flag, name, forward_kind);
       break;
 
     case CTF_K_TYPEDEF:
@@ -1916,18 +1970,31 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type)
       return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
     }
 
+  if (dst_type != CTF_ERR)
+    ctf_add_type_mapping (src_fp, orig_src_type, dst_fp, dst_type);
   return dst_type;
 }
 
-/* Write the compressed CTF data stream to the specified gzFile descriptor.
-   This is useful for saving the results of dynamic CTF containers.  */
+/* Write the compressed CTF data stream to the specified gzFile descriptor.  */
 int
 ctf_gzwrite (ctf_file_t *fp, gzFile fd)
 {
-  const unsigned char *buf = fp->ctf_base;
-  ssize_t resid = fp->ctf_size;
+  const unsigned char *buf;
+  ssize_t resid;
   ssize_t len;
 
+  resid = sizeof (ctf_header_t);
+  buf = (unsigned char *) fp->ctf_header;
+  while (resid != 0)
+    {
+      if ((len = gzwrite (fd, buf, resid)) <= 0)
+       return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  resid = fp->ctf_size;
+  buf = fp->ctf_buf;
   while (resid != 0)
     {
       if ((len = gzwrite (fd, buf, resid)) <= 0)
@@ -1950,12 +2017,12 @@ ctf_compress_write (ctf_file_t *fp, int fd)
   ctf_header_t *hp = &h;
   ssize_t header_len = sizeof (ctf_header_t);
   ssize_t compress_len;
-  size_t max_compress_len = compressBound (fp->ctf_size - header_len);
+  size_t max_compress_len = compressBound (fp->ctf_size);
   ssize_t len;
   int rc;
   int err = 0;
 
-  memcpy (hp, fp->ctf_base, header_len);
+  memcpy (hp, fp->ctf_header, header_len);
   hp->cth_flags |= CTF_F_COMPRESS;
 
   if ((buf = ctf_alloc (max_compress_len)) == NULL)
@@ -1963,12 +2030,10 @@ ctf_compress_write (ctf_file_t *fp, int fd)
 
   compress_len = max_compress_len;
   if ((rc = compress (buf, (uLongf *) &compress_len,
-                     fp->ctf_base + header_len,
-                     fp->ctf_size - header_len)) != Z_OK)
+                     fp->ctf_buf, fp->ctf_size)) != Z_OK)
     {
       ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
       err = ctf_set_errno (fp, ECTF_COMPRESS);
-      ctf_free (buf);
       goto ret;
     }
 
@@ -2000,18 +2065,80 @@ ret:
   return err;
 }
 
-/* Write the uncompressed CTF data stream to the specified file descriptor.
-   This is useful for saving the results of dynamic CTF containers.  */
+/* Optionally compress the specified CTF data stream and return it as a new
+   dynamically-allocated string.  */
+unsigned char *
+ctf_write_mem (ctf_file_t *fp, size_t *size, size_t threshold)
+{
+  unsigned char *buf;
+  unsigned char *bp;
+  ctf_header_t *hp;
+  ssize_t header_len = sizeof (ctf_header_t);
+  ssize_t compress_len;
+  size_t max_compress_len = compressBound (fp->ctf_size);
+  int rc;
+
+  if (fp->ctf_size < threshold)
+    max_compress_len = fp->ctf_size;
+  if ((buf = malloc (max_compress_len
+                    + sizeof (struct ctf_header))) == NULL)
+    {
+      ctf_set_errno (fp, ENOMEM);
+      return NULL;
+    }
+
+  hp = (ctf_header_t *) buf;
+  memcpy (hp, fp->ctf_header, header_len);
+  bp = buf + sizeof (struct ctf_header);
+  *size = sizeof (struct ctf_header);
+
+  compress_len = max_compress_len;
+
+  if (fp->ctf_size < threshold)
+    {
+      hp->cth_flags &= ~CTF_F_COMPRESS;
+      memcpy (bp, fp->ctf_buf, fp->ctf_size);
+      *size += fp->ctf_size;
+    }
+  else
+    {
+      hp->cth_flags |= CTF_F_COMPRESS;
+      if ((rc = compress (bp, (uLongf *) &compress_len,
+                         fp->ctf_buf, fp->ctf_size)) != Z_OK)
+       {
+         ctf_dprintf ("zlib deflate err: %s\n", zError (rc));
+         ctf_set_errno (fp, ECTF_COMPRESS);
+         ctf_free (buf);
+         return NULL;
+       }
+      *size += compress_len;
+    }
+  return buf;
+}
+
+/* Write the uncompressed CTF data stream to the specified file descriptor.  */
 int
 ctf_write (ctf_file_t *fp, int fd)
 {
-  const unsigned char *buf = fp->ctf_base;
-  ssize_t resid = fp->ctf_size;
+  const unsigned char *buf;
+  ssize_t resid;
   ssize_t len;
 
+  resid = sizeof (ctf_header_t);
+  buf = (unsigned char *) fp->ctf_header;
+  while (resid != 0)
+    {
+      if ((len = write (fd, buf, resid)) <= 0)
+       return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  resid = fp->ctf_size;
+  buf = fp->ctf_buf;
   while (resid != 0)
     {
-      if ((len = write (fd, buf, resid)) < 0)
+      if ((len = write (fd, buf, resid)) <= 0)
        return (ctf_set_errno (fp, errno));
       resid -= len;
       buf += len;
This page took 0.029293 seconds and 4 git commands to generate.