172132Ssemenu/* Miscellaneous utilities. 272132Ssemenu Copyright (C) 2019-2020 Free Software Foundation, Inc. 372132Ssemenu 472132Ssemenu This file is part of libctf. 572132Ssemenu 672132Ssemenu libctf is free software; you can redistribute it and/or modify it under 772132Ssemenu the terms of the GNU General Public License as published by the Free 872132Ssemenu Software Foundation; either version 3, or (at your option) any later 972132Ssemenu version. 1072132Ssemenu 1172132Ssemenu This program is distributed in the hope that it will be useful, but 1272132Ssemenu WITHOUT ANY WARRANTY; without even the implied warranty of 1372132Ssemenu MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1472132Ssemenu See the GNU General Public License for more details. 1572132Ssemenu 1672132Ssemenu You should have received a copy of the GNU General Public License 1772132Ssemenu along with this program; see the file COPYING. If not see 1872132Ssemenu <http://www.gnu.org/licenses/>. */ 1972132Ssemenu 2072132Ssemenu#include <ctf-impl.h> 2172132Ssemenu#include <string.h> 2272132Ssemenu 2372132Ssemenu/* Simple doubly-linked list append routine. This implementation assumes that 2472132Ssemenu each list element contains an embedded ctf_list_t as the first member. 2572132Ssemenu An additional ctf_list_t is used to store the head (l_next) and tail 2672132Ssemenu (l_prev) pointers. The current head and tail list elements have their 2772132Ssemenu previous and next pointers set to NULL, respectively. */ 2872132Ssemenu 2972132Ssemenuvoid 3072132Ssemenuctf_list_append (ctf_list_t *lp, void *newp) 3172132Ssemenu{ 3272132Ssemenu ctf_list_t *p = lp->l_prev; /* p = tail list element. */ 3372132Ssemenu ctf_list_t *q = newp; /* q = new list element. */ 34139749Simp 3572132Ssemenu lp->l_prev = q; 3672132Ssemenu q->l_prev = p; 3772132Ssemenu q->l_next = NULL; 3872132Ssemenu 3972132Ssemenu if (p != NULL) 4072132Ssemenu p->l_next = q; 4172132Ssemenu else 4272132Ssemenu lp->l_next = q; 4372132Ssemenu} 4472132Ssemenu 4572132Ssemenu/* Prepend the specified existing element to the given ctf_list_t. The 4672132Ssemenu existing pointer should be pointing at a struct with embedded ctf_list_t. */ 4772132Ssemenu 4872132Ssemenuvoid 4972132Ssemenuctf_list_prepend (ctf_list_t * lp, void *newp) 5072132Ssemenu{ 5172132Ssemenu ctf_list_t *p = newp; /* p = new list element. */ 5272132Ssemenu ctf_list_t *q = lp->l_next; /* q = head list element. */ 5372132Ssemenu 5472132Ssemenu lp->l_next = p; 5572132Ssemenu p->l_prev = NULL; 5672132Ssemenu p->l_next = q; 5772132Ssemenu 58129844Smarius if (q != NULL) 59129844Smarius q->l_prev = p; 60129844Smarius else 6172132Ssemenu lp->l_prev = p; 6272132Ssemenu} 6372132Ssemenu 6472132Ssemenu/* Delete the specified existing element from the given ctf_list_t. The 6572132Ssemenu existing pointer should be pointing at a struct with embedded ctf_list_t. */ 6672132Ssemenu 6772132Ssemenuvoid 6872132Ssemenuctf_list_delete (ctf_list_t *lp, void *existing) 6972132Ssemenu{ 7072132Ssemenu ctf_list_t *p = existing; 7172132Ssemenu 7272132Ssemenu if (p->l_prev != NULL) 7372132Ssemenu p->l_prev->l_next = p->l_next; 7472132Ssemenu else 7572132Ssemenu lp->l_next = p->l_next; 7672132Ssemenu 7772132Ssemenu if (p->l_next != NULL) 7872132Ssemenu p->l_next->l_prev = p->l_prev; 79109514Sobrien else 8072132Ssemenu lp->l_prev = p->l_prev; 8172132Ssemenu} 8272132Ssemenu 8372132Ssemenu/* Return 1 if the list is empty. */ 8472132Ssemenu 85105135Salfredint 86105135Salfredctf_list_empty_p (ctf_list_t *lp) 8772132Ssemenu{ 8872132Ssemenu return (lp->l_next == NULL && lp->l_prev == NULL); 8972132Ssemenu} 9072132Ssemenu 9172132Ssemenu/* Convert a 32-bit ELF symbol into Elf64 and return a pointer to it. */ 9295722Sphk 9372132SsemenuElf64_Sym * 94227908Smariusctf_sym_to_elf64 (const Elf32_Sym *src, Elf64_Sym *dst) 9572132Ssemenu{ 9672132Ssemenu dst->st_name = src->st_name; 9772132Ssemenu dst->st_value = src->st_value; 9872132Ssemenu dst->st_size = src->st_size; 9972132Ssemenu dst->st_info = src->st_info; 10072132Ssemenu dst->st_other = src->st_other; 10172132Ssemenu dst->st_shndx = src->st_shndx; 10272132Ssemenu 10372132Ssemenu return dst; 10472132Ssemenu} 10572132Ssemenu 10672132Ssemenu/* A string appender working on dynamic strings. Returns NULL on OOM. */ 10792739Salfred 10892739Salfredchar * 10992739Salfredctf_str_append (char *s, const char *append) 11072132Ssemenu{ 111164827Smarius size_t s_len = 0; 112221407Smarius 113164827Smarius if (append == NULL) 114164827Smarius return s; 115164827Smarius 116221407Smarius if (s != NULL) 117221407Smarius s_len = strlen (s); 118221407Smarius 119221407Smarius size_t append_len = strlen (append); 120221407Smarius 121221407Smarius if ((s = realloc (s, s_len + append_len + 1)) == NULL) 122105135Salfred return NULL; 123150763Simp 12472132Ssemenu memcpy (s + s_len, append, append_len); 12572132Ssemenu s[s_len + append_len] = '\0'; 126164827Smarius 12772132Ssemenu return s; 12872132Ssemenu} 129105135Salfred 130150763Simp/* A version of ctf_str_append that returns the old string on OOM. */ 13172132Ssemenu 13272132Ssemenuchar * 133221407Smariusctf_str_append_noerr (char *s, const char *append) 13472132Ssemenu{ 13572132Ssemenu char *new_s; 13672132Ssemenu 13784145Sjlemon new_s = ctf_str_append (s, append); 138150763Simp if (!new_s) 13972132Ssemenu return s; 14072132Ssemenu return new_s; 14172132Ssemenu} 14272132Ssemenu 14372132Ssemenu/* A realloc() that fails noisily if called with any ctf_str_num_users. */ 14472132Ssemenuvoid * 14572132Ssemenuctf_realloc (ctf_file_t *fp, void *ptr, size_t size) 14672132Ssemenu{ 14772132Ssemenu if (fp->ctf_str_num_refs > 0) 14872132Ssemenu { 14972132Ssemenu ctf_dprintf ("%p: attempt to realloc() string table with %lu active refs\n", 15072132Ssemenu (void *) fp, (unsigned long) fp->ctf_str_num_refs); 15172132Ssemenu return NULL; 152164710Smarius } 15372132Ssemenu return realloc (ptr, size); 15472132Ssemenu} 15572132Ssemenu 15672132Ssemenu/* Store the specified error code into errp if it is non-NULL, and then 15784145Sjlemon return NULL for the benefit of the caller. */ 15872132Ssemenu 15984145Sjlemonvoid * 16072132Ssemenuctf_set_open_errno (int *errp, int error) 16172132Ssemenu{ 16272132Ssemenu if (errp != NULL) 16395877Ssemenu *errp = error; 16472132Ssemenu return NULL; 16572132Ssemenu} 16672132Ssemenu 16772132Ssemenu/* Store the specified error code into the CTF container, and then return 16872132Ssemenu CTF_ERR / -1 for the benefit of the caller. */ 169221407Smarius 17072132Ssemenuunsigned long 17172132Ssemenuctf_set_errno (ctf_file_t * fp, int err) 17284145Sjlemon{ 17372132Ssemenu fp->ctf_errno = err; 17472132Ssemenu return CTF_ERR; 17572132Ssemenu} 17684145Sjlemon