libctf: low-level list manipulation and helper utilities
authorNick Alcock <nick.alcock@oracle.com>
Tue, 23 Apr 2019 20:45:30 +0000 (21:45 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Tue, 28 May 2019 16:07:19 +0000 (17:07 +0100)
These utilities are a bit of a ragbag of small things needed by more
than one TU: list manipulation, ELF32->64 translators, routines to look
up strings in string tables, dynamically-allocated string appenders, and
routines to set the specialized errno values previously committed in
<ctf-api.h>.

We do still need to dig around in raw ELF symbol tables in places,
because libctf allows the caller to pass in the contents of string and
symbol sections without telling it where they come from, so we cannot
use BFD to get the symbols (BFD reasonably demands the entire file).  So
extract minimal ELF definitions from glibc into a private header named
libctf/elf.h: later, we use those to get symbols.  (The start-of-
copyright range on elf.h reflects this glibc heritage.)

libctf/
* ctf-util.c: New file.
* elf.h: Likewise.
* ctf-impl.h: Include it, and add declarations.

libctf/ChangeLog
libctf/ctf-impl.h
libctf/ctf-util.c [new file with mode: 0644]
libctf/elf.h [new file with mode: 0644]

index 6a37212d8b6167f5db76d50e50bd7d15cc3ce968..7648c268ce9dbcb6634a2ba5f3c8674e83634f18 100644 (file)
@@ -1,3 +1,9 @@
+2019-05-28  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-util.c: New file.
+       * elf.h: Likewise.
+       * ctf-impl.h: Include it, and add declarations.
+
 2019-05-28  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-impl.h: New file.
index 4356a2a9f0feeb5c70ab17a4639abcd577ab03ec..268b2f343f7ae960f9a729c383f5c37cdd25c82b 100644 (file)
 #include <sys/errno.h>
 #include <ctf-api.h>
 #include <sys/types.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <ctype.h>
+#include <elf.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -51,6 +58,25 @@ extern "C"
 
 #endif
 
+typedef struct ctf_list
+{
+  struct ctf_list *l_prev;     /* Previous pointer or tail pointer.  */
+  struct ctf_list *l_next;     /* Next pointer or head pointer.  */
+} ctf_list_t;
+
+#define        ctf_list_prev(elem)     ((void *)(((ctf_list_t *)(elem))->l_prev))
+#define        ctf_list_next(elem)     ((void *)(((ctf_list_t *)(elem))->l_next))
+
+extern void ctf_list_append (ctf_list_t *, void *);
+extern void ctf_list_prepend (ctf_list_t *, void *);
+extern void ctf_list_delete (ctf_list_t *, void *);
+
+extern const char *ctf_strraw (ctf_file_t *, uint32_t);
+extern const char *ctf_strptr (ctf_file_t *, uint32_t);
+
+extern void *ctf_set_open_errno (int *, int);
+extern long ctf_set_errno (ctf_file_t *, int);
+
 _libctf_malloc_
 extern void *ctf_data_alloc (size_t);
 extern void ctf_data_free (void *, size_t);
@@ -65,10 +91,17 @@ _libctf_malloc_
 extern void *ctf_alloc (size_t);
 extern void ctf_free (void *);
 
+_libctf_malloc_
+extern char *ctf_strdup (const char *);
+extern char *ctf_str_append (char *, const char *);
+extern const char *ctf_strerror (int);
+
 _libctf_printflike_ (1, 2)
 extern void ctf_dprintf (const char *, ...);
 extern void libctf_init_debug (void);
 
+extern Elf64_Sym *ctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst);
+
 extern int _libctf_debug;      /* debugging messages enabled */
 
 #ifdef __cplusplus
diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c
new file mode 100644 (file)
index 0000000..4460046
--- /dev/null
@@ -0,0 +1,176 @@
+/* Miscellaneous utilities.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <string.h>
+
+/* Simple doubly-linked list append routine.  This implementation assumes that
+   each list element contains an embedded ctf_list_t as the first member.
+   An additional ctf_list_t is used to store the head (l_next) and tail
+   (l_prev) pointers.  The current head and tail list elements have their
+   previous and next pointers set to NULL, respectively.  */
+
+void
+ctf_list_append (ctf_list_t *lp, void *newp)
+{
+  ctf_list_t *p = lp->l_prev;  /* p = tail list element.  */
+  ctf_list_t *q = newp;                /* q = new list element.  */
+
+  lp->l_prev = q;
+  q->l_prev = p;
+  q->l_next = NULL;
+
+  if (p != NULL)
+    p->l_next = q;
+  else
+    lp->l_next = q;
+}
+
+/* Prepend the specified existing element to the given ctf_list_t.  The
+   existing pointer should be pointing at a struct with embedded ctf_list_t.  */
+
+void
+ctf_list_prepend (ctf_list_t * lp, void *newp)
+{
+  ctf_list_t *p = newp;                /* p = new list element.  */
+  ctf_list_t *q = lp->l_next;  /* q = head list element.  */
+
+  lp->l_next = p;
+  p->l_prev = NULL;
+  p->l_next = q;
+
+  if (q != NULL)
+    q->l_prev = p;
+  else
+    lp->l_prev = p;
+}
+
+/* Delete the specified existing element from the given ctf_list_t.  The
+   existing pointer should be pointing at a struct with embedded ctf_list_t.  */
+
+void
+ctf_list_delete (ctf_list_t *lp, void *existing)
+{
+  ctf_list_t *p = existing;
+
+  if (p->l_prev != NULL)
+    p->l_prev->l_next = p->l_next;
+  else
+    lp->l_next = p->l_next;
+
+  if (p->l_next != NULL)
+    p->l_next->l_prev = p->l_prev;
+  else
+    lp->l_prev = p->l_prev;
+}
+
+/* Convert a 32-bit ELF symbol into Elf64 and return a pointer to it.  */
+
+Elf64_Sym *
+ctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst)
+{
+  dst->st_name = src->st_name;
+  dst->st_value = src->st_value;
+  dst->st_size = src->st_size;
+  dst->st_info = src->st_info;
+  dst->st_other = src->st_other;
+  dst->st_shndx = src->st_shndx;
+
+  return dst;
+}
+
+/* Convert an encoded CTF string name into a pointer to a C string by looking
+  up the appropriate string table buffer and then adding the offset.  */
+
+const char *
+ctf_strraw (ctf_file_t *fp, uint32_t name)
+{
+  ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)];
+
+  if (ctsp->cts_strs != NULL && CTF_NAME_OFFSET (name) < ctsp->cts_len)
+    return (ctsp->cts_strs + CTF_NAME_OFFSET (name));
+
+  /* String table not loaded or corrupt offset.  */
+  return NULL;
+}
+
+const char *
+ctf_strptr (ctf_file_t *fp, uint32_t name)
+{
+  const char *s = ctf_strraw (fp, name);
+  return (s != NULL ? s : "(?)");
+}
+
+/* Same as strdup(3C), but use ctf_alloc() to do the memory allocation. */
+
+_libctf_malloc_ char *
+ctf_strdup (const char *s1)
+{
+  char *s2 = ctf_alloc (strlen (s1) + 1);
+
+  if (s2 != NULL)
+    (void) strcpy (s2, s1);
+
+  return s2;
+}
+
+/* A string appender working on dynamic strings.  */
+
+char *
+ctf_str_append (char *s, const char *append)
+{
+  size_t s_len = 0;
+
+  if (append == NULL)
+    return s;
+
+  if (s != NULL)
+    s_len = strlen (s);
+
+  size_t append_len = strlen (append);
+
+  if ((s = realloc (s, s_len + append_len + 1)) == NULL)
+    return NULL;
+
+  memcpy (s + s_len, append, append_len);
+  s[s_len + append_len] = '\0';
+
+  return s;
+}
+
+/* Store the specified error code into errp if it is non-NULL, and then
+   return NULL for the benefit of the caller.  */
+
+void *
+ctf_set_open_errno (int *errp, int error)
+{
+  if (errp != NULL)
+    *errp = error;
+  return NULL;
+}
+
+/* Store the specified error code into the CTF container, and then return
+   CTF_ERR for the benefit of the caller. */
+
+long
+ctf_set_errno (ctf_file_t * fp, int err)
+{
+  fp->ctf_errno = err;
+  return CTF_ERR;
+}
diff --git a/libctf/elf.h b/libctf/elf.h
new file mode 100644 (file)
index 0000000..fee1630
--- /dev/null
@@ -0,0 +1,61 @@
+/* This file defines standard ELF types, structures, and macros.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _CTF_ELF_H
+#define _CTF_ELF_H
+
+#include "config.h"
+#include "ansidecl.h"
+#include <stdint.h>
+#include "elf/common.h"
+#include "elf/external.h"
+
+typedef uint32_t Elf32_Word;
+typedef uint32_t Elf64_Word;
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Xword;
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+#define SHN_EXTABS     0xFFF1          /* Associated symbol is absolute */
+
+/* Symbol table entry.  */
+
+typedef struct
+{
+  Elf32_Word   st_name;                /* Symbol name (string tbl index) */
+  Elf32_Addr   st_value;               /* Symbol value */
+  Elf32_Word   st_size;                /* Symbol size */
+  unsigned char        st_info;                /* Symbol type and binding */
+  unsigned char        st_other;               /* Symbol visibility */
+  Elf32_Section        st_shndx;               /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word   st_name;                /* Symbol name (string tbl index) */
+  unsigned char        st_info;                /* Symbol type and binding */
+  unsigned char st_other;              /* Symbol visibility */
+  Elf64_Section        st_shndx;               /* Section index */
+  Elf64_Addr   st_value;               /* Symbol value */
+  Elf64_Xword  st_size;                /* Symbol size */
+} Elf64_Sym;
+
+#endif /* _CTF_ELF_H */