1 /* Miscellaneous utilities. 2 Copyright (C) 2019-2024 Free Software Foundation, Inc. 3 4 This file is part of libctf. 5 6 libctf is free software; you can redistribute it and/or modify it under 7 the terms of the GNU General Public License as published by the Free 8 Software Foundation; either version 3, or (at your option) any later 9 version. 10 11 This program is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 See the GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; see the file COPYING. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include <ctf-impl.h> 21 #include <string.h> 22 #include "ctf-endian.h" 23 24 /* Simple doubly-linked list append routine. This implementation assumes that 25 each list element contains an embedded ctf_list_t as the first member. 26 An additional ctf_list_t is used to store the head (l_next) and tail 27 (l_prev) pointers. The current head and tail list elements have their 28 previous and next pointers set to NULL, respectively. */ 29 30 void 31 ctf_list_append (ctf_list_t *lp, void *newp) 32 { 33 ctf_list_t *p = lp->l_prev; /* p = tail list element. */ 34 ctf_list_t *q = newp; /* q = new list element. */ 35 36 lp->l_prev = q; 37 q->l_prev = p; 38 q->l_next = NULL; 39 40 if (p != NULL) 41 p->l_next = q; 42 else 43 lp->l_next = q; 44 } 45 46 /* Prepend the specified existing element to the given ctf_list_t. The 47 existing pointer should be pointing at a struct with embedded ctf_list_t. */ 48 49 void 50 ctf_list_prepend (ctf_list_t * lp, void *newp) 51 { 52 ctf_list_t *p = newp; /* p = new list element. */ 53 ctf_list_t *q = lp->l_next; /* q = head list element. */ 54 55 lp->l_next = p; 56 p->l_prev = NULL; 57 p->l_next = q; 58 59 if (q != NULL) 60 q->l_prev = p; 61 else 62 lp->l_prev = p; 63 } 64 65 /* Delete the specified existing element from the given ctf_list_t. The 66 existing pointer should be pointing at a struct with embedded ctf_list_t. */ 67 68 void 69 ctf_list_delete (ctf_list_t *lp, void *existing) 70 { 71 ctf_list_t *p = existing; 72 73 if (p->l_prev != NULL) 74 p->l_prev->l_next = p->l_next; 75 else 76 lp->l_next = p->l_next; 77 78 if (p->l_next != NULL) 79 p->l_next->l_prev = p->l_prev; 80 else 81 lp->l_prev = p->l_prev; 82 } 83 84 /* Return 1 if the list is empty. */ 85 86 int 87 ctf_list_empty_p (ctf_list_t *lp) 88 { 89 return (lp->l_next == NULL && lp->l_prev == NULL); 90 } 91 92 /* Splice one entire list onto the end of another one. The existing list is 93 emptied. */ 94 95 void 96 ctf_list_splice (ctf_list_t *lp, ctf_list_t *append) 97 { 98 if (ctf_list_empty_p (append)) 99 return; 100 101 if (lp->l_prev != NULL) 102 lp->l_prev->l_next = append->l_next; 103 else 104 lp->l_next = append->l_next; 105 106 append->l_next->l_prev = lp->l_prev; 107 lp->l_prev = append->l_prev; 108 append->l_next = NULL; 109 append->l_prev = NULL; 110 } 111 112 /* Convert a 32-bit ELF symbol to a ctf_link_sym_t. */ 113 114 ctf_link_sym_t * 115 ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf32_Sym *src, 116 uint32_t symidx) 117 { 118 Elf32_Sym tmp; 119 int needs_flipping = 0; 120 121 #ifdef WORDS_BIGENDIAN 122 if (fp->ctf_symsect_little_endian) 123 needs_flipping = 1; 124 #else 125 if (!fp->ctf_symsect_little_endian) 126 needs_flipping = 1; 127 #endif 128 129 memcpy (&tmp, src, sizeof (Elf32_Sym)); 130 if (needs_flipping) 131 { 132 swap_thing (tmp.st_name); 133 swap_thing (tmp.st_size); 134 swap_thing (tmp.st_shndx); 135 swap_thing (tmp.st_value); 136 } 137 /* The name must be in the external string table. */ 138 if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len) 139 dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name; 140 else 141 dst->st_name = _CTF_NULLSTR; 142 dst->st_nameidx_set = 0; 143 dst->st_symidx = symidx; 144 dst->st_shndx = tmp.st_shndx; 145 dst->st_type = ELF32_ST_TYPE (tmp.st_info); 146 dst->st_value = tmp.st_value; 147 148 return dst; 149 } 150 151 /* Convert a 64-bit ELF symbol to a ctf_link_sym_t. */ 152 153 ctf_link_sym_t * 154 ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src, 155 uint32_t symidx) 156 { 157 Elf64_Sym tmp; 158 int needs_flipping = 0; 159 160 #ifdef WORDS_BIGENDIAN 161 if (fp->ctf_symsect_little_endian) 162 needs_flipping = 1; 163 #else 164 if (!fp->ctf_symsect_little_endian) 165 needs_flipping = 1; 166 #endif 167 168 memcpy (&tmp, src, sizeof (Elf64_Sym)); 169 if (needs_flipping) 170 { 171 swap_thing (tmp.st_name); 172 swap_thing (tmp.st_size); 173 swap_thing (tmp.st_shndx); 174 swap_thing (tmp.st_value); 175 } 176 177 /* The name must be in the external string table. */ 178 if (tmp.st_name < fp->ctf_str[CTF_STRTAB_1].cts_len) 179 dst->st_name = (const char *) fp->ctf_str[CTF_STRTAB_1].cts_strs + tmp.st_name; 180 else 181 dst->st_name = _CTF_NULLSTR; 182 dst->st_nameidx_set = 0; 183 dst->st_symidx = symidx; 184 dst->st_shndx = tmp.st_shndx; 185 dst->st_type = ELF32_ST_TYPE (tmp.st_info); 186 187 /* We only care if the value is zero, so avoid nonzeroes turning into 188 zeroes. */ 189 if (_libctf_unlikely_ (tmp.st_value != 0 && ((uint32_t) tmp.st_value == 0))) 190 dst->st_value = 1; 191 else 192 dst->st_value = (uint32_t) tmp.st_value; 193 194 return dst; 195 } 196 197 /* A string appender working on dynamic strings. Returns NULL on OOM. */ 198 199 char * 200 ctf_str_append (char *s, const char *append) 201 { 202 size_t s_len = 0; 203 204 if (append == NULL) 205 return s; 206 207 if (s != NULL) 208 s_len = strlen (s); 209 210 size_t append_len = strlen (append); 211 212 if ((s = realloc (s, s_len + append_len + 1)) == NULL) 213 return NULL; 214 215 memcpy (s + s_len, append, append_len); 216 s[s_len + append_len] = '\0'; 217 218 return s; 219 } 220 221 /* A version of ctf_str_append that returns the old string on OOM. */ 222 223 char * 224 ctf_str_append_noerr (char *s, const char *append) 225 { 226 char *new_s; 227 228 new_s = ctf_str_append (s, append); 229 if (!new_s) 230 return s; 231 return new_s; 232 } 233 234 /* Store the specified error code into errp if it is non-NULL, and then 235 return NULL for the benefit of the caller. */ 236 237 void * 238 ctf_set_open_errno (int *errp, int error) 239 { 240 if (errp != NULL) 241 *errp = error; 242 return NULL; 243 } 244 245 /* Create a ctf_next_t. */ 246 247 ctf_next_t * 248 ctf_next_create (void) 249 { 250 return calloc (1, sizeof (struct ctf_next)); 251 } 252 253 /* Destroy a ctf_next_t, for early exit from iterators. */ 254 255 void 256 ctf_next_destroy (ctf_next_t *i) 257 { 258 if (i == NULL) 259 return; 260 261 if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) 262 free (i->u.ctn_sorted_hkv); 263 if (i->ctn_next) 264 ctf_next_destroy (i->ctn_next); 265 free (i); 266 } 267 268 /* Copy a ctf_next_t. */ 269 270 ctf_next_t * 271 ctf_next_copy (ctf_next_t *i) 272 { 273 ctf_next_t *i2; 274 275 if ((i2 = ctf_next_create()) == NULL) 276 return NULL; 277 memcpy (i2, i, sizeof (struct ctf_next)); 278 279 if (i2->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) 280 { 281 size_t els = ctf_dynhash_elements ((ctf_dynhash_t *) i->cu.ctn_h); 282 if ((i2->u.ctn_sorted_hkv = calloc (els, sizeof (ctf_next_hkv_t))) == NULL) 283 { 284 free (i2); 285 return NULL; 286 } 287 memcpy (i2->u.ctn_sorted_hkv, i->u.ctn_sorted_hkv, 288 els * sizeof (ctf_next_hkv_t)); 289 } 290 return i2; 291 } 292