1da0c48c4Sopenharmony_ci/* ELF/DWARF string table handling. 2da0c48c4Sopenharmony_ci Copyright (C) 2000, 2001, 2002, 2005, 2016 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2000. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of either 8da0c48c4Sopenharmony_ci 9da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 10da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 11da0c48c4Sopenharmony_ci your option) any later version 12da0c48c4Sopenharmony_ci 13da0c48c4Sopenharmony_ci or 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 16da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 17da0c48c4Sopenharmony_ci your option) any later version 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci or both in parallel, as here. 20da0c48c4Sopenharmony_ci 21da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 22da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 23da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24da0c48c4Sopenharmony_ci General Public License for more details. 25da0c48c4Sopenharmony_ci 26da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 27da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 28da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 29da0c48c4Sopenharmony_ci 30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 31da0c48c4Sopenharmony_ci# include <config.h> 32da0c48c4Sopenharmony_ci#endif 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include <assert.h> 35da0c48c4Sopenharmony_ci#include <inttypes.h> 36da0c48c4Sopenharmony_ci#include <libelf.h> 37da0c48c4Sopenharmony_ci#include <stddef.h> 38da0c48c4Sopenharmony_ci#include <stdlib.h> 39da0c48c4Sopenharmony_ci#include <string.h> 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_ci#include "libdwelfP.h" 42da0c48c4Sopenharmony_ci#include <system.h> 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci 45da0c48c4Sopenharmony_cistruct Dwelf_Strent 46da0c48c4Sopenharmony_ci{ 47da0c48c4Sopenharmony_ci const char *string; 48da0c48c4Sopenharmony_ci size_t len; 49da0c48c4Sopenharmony_ci struct Dwelf_Strent *next; 50da0c48c4Sopenharmony_ci struct Dwelf_Strent *left; 51da0c48c4Sopenharmony_ci struct Dwelf_Strent *right; 52da0c48c4Sopenharmony_ci size_t offset; 53da0c48c4Sopenharmony_ci char reverse[0]; 54da0c48c4Sopenharmony_ci}; 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_ci 57da0c48c4Sopenharmony_cistruct memoryblock 58da0c48c4Sopenharmony_ci{ 59da0c48c4Sopenharmony_ci struct memoryblock *next; 60da0c48c4Sopenharmony_ci char memory[0]; 61da0c48c4Sopenharmony_ci}; 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_ci 64da0c48c4Sopenharmony_cistruct Dwelf_Strtab 65da0c48c4Sopenharmony_ci{ 66da0c48c4Sopenharmony_ci struct Dwelf_Strent *root; 67da0c48c4Sopenharmony_ci struct memoryblock *memory; 68da0c48c4Sopenharmony_ci char *backp; 69da0c48c4Sopenharmony_ci size_t left; 70da0c48c4Sopenharmony_ci size_t total; 71da0c48c4Sopenharmony_ci bool nullstr; 72da0c48c4Sopenharmony_ci 73da0c48c4Sopenharmony_ci struct Dwelf_Strent null; 74da0c48c4Sopenharmony_ci}; 75da0c48c4Sopenharmony_ci 76da0c48c4Sopenharmony_ci 77da0c48c4Sopenharmony_ci/* Cache for the pagesize. */ 78da0c48c4Sopenharmony_cistatic size_t ps; 79da0c48c4Sopenharmony_ci/* We correct this value a bit so that `malloc' is not allocating more 80da0c48c4Sopenharmony_ci than a page. */ 81da0c48c4Sopenharmony_ci#define MALLOC_OVERHEAD (2 * sizeof (void *)) 82da0c48c4Sopenharmony_ci 83da0c48c4Sopenharmony_ci 84da0c48c4Sopenharmony_ciDwelf_Strtab * 85da0c48c4Sopenharmony_cidwelf_strtab_init (bool nullstr) 86da0c48c4Sopenharmony_ci{ 87da0c48c4Sopenharmony_ci if (ps == 0) 88da0c48c4Sopenharmony_ci { 89da0c48c4Sopenharmony_ci ps = sysconf (_SC_PAGESIZE); 90da0c48c4Sopenharmony_ci assert (sizeof (struct memoryblock) < ps - MALLOC_OVERHEAD); 91da0c48c4Sopenharmony_ci } 92da0c48c4Sopenharmony_ci 93da0c48c4Sopenharmony_ci Dwelf_Strtab *ret = calloc (1, sizeof (struct Dwelf_Strtab)); 94da0c48c4Sopenharmony_ci if (ret != NULL) 95da0c48c4Sopenharmony_ci { 96da0c48c4Sopenharmony_ci ret->nullstr = nullstr; 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci if (nullstr) 99da0c48c4Sopenharmony_ci { 100da0c48c4Sopenharmony_ci ret->null.len = 1; 101da0c48c4Sopenharmony_ci ret->null.string = ""; 102da0c48c4Sopenharmony_ci } 103da0c48c4Sopenharmony_ci } 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ci return ret; 106da0c48c4Sopenharmony_ci} 107da0c48c4Sopenharmony_ci 108da0c48c4Sopenharmony_ci 109da0c48c4Sopenharmony_cistatic int 110da0c48c4Sopenharmony_cimorememory (Dwelf_Strtab *st, size_t len) 111da0c48c4Sopenharmony_ci{ 112da0c48c4Sopenharmony_ci size_t overhead = offsetof (struct memoryblock, memory); 113da0c48c4Sopenharmony_ci len += overhead + MALLOC_OVERHEAD; 114da0c48c4Sopenharmony_ci 115da0c48c4Sopenharmony_ci /* Allocate nearest multiple of pagesize >= len. */ 116da0c48c4Sopenharmony_ci len = ((len / ps) + (len % ps != 0)) * ps - MALLOC_OVERHEAD; 117da0c48c4Sopenharmony_ci 118da0c48c4Sopenharmony_ci struct memoryblock *newmem = malloc (len); 119da0c48c4Sopenharmony_ci if (newmem == NULL) 120da0c48c4Sopenharmony_ci return 1; 121da0c48c4Sopenharmony_ci 122da0c48c4Sopenharmony_ci newmem->next = st->memory; 123da0c48c4Sopenharmony_ci st->memory = newmem; 124da0c48c4Sopenharmony_ci st->backp = newmem->memory; 125da0c48c4Sopenharmony_ci st->left = len - overhead; 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ci return 0; 128da0c48c4Sopenharmony_ci} 129da0c48c4Sopenharmony_ci 130da0c48c4Sopenharmony_ci 131da0c48c4Sopenharmony_civoid 132da0c48c4Sopenharmony_cidwelf_strtab_free (Dwelf_Strtab *st) 133da0c48c4Sopenharmony_ci{ 134da0c48c4Sopenharmony_ci struct memoryblock *mb = st->memory; 135da0c48c4Sopenharmony_ci 136da0c48c4Sopenharmony_ci while (mb != NULL) 137da0c48c4Sopenharmony_ci { 138da0c48c4Sopenharmony_ci void *old = mb; 139da0c48c4Sopenharmony_ci mb = mb->next; 140da0c48c4Sopenharmony_ci free (old); 141da0c48c4Sopenharmony_ci } 142da0c48c4Sopenharmony_ci 143da0c48c4Sopenharmony_ci free (st); 144da0c48c4Sopenharmony_ci} 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_ci 147da0c48c4Sopenharmony_cistatic Dwelf_Strent * 148da0c48c4Sopenharmony_cinewstring (Dwelf_Strtab *st, const char *str, size_t len) 149da0c48c4Sopenharmony_ci{ 150da0c48c4Sopenharmony_ci /* Compute the amount of padding needed to make the structure aligned. */ 151da0c48c4Sopenharmony_ci size_t align = ((__alignof__ (struct Dwelf_Strent) 152da0c48c4Sopenharmony_ci - (((uintptr_t) st->backp) 153da0c48c4Sopenharmony_ci & (__alignof__ (struct Dwelf_Strent) - 1))) 154da0c48c4Sopenharmony_ci & (__alignof__ (struct Dwelf_Strent) - 1)); 155da0c48c4Sopenharmony_ci 156da0c48c4Sopenharmony_ci /* Make sure there is enough room in the memory block. */ 157da0c48c4Sopenharmony_ci if (st->left < align + sizeof (struct Dwelf_Strent) + len) 158da0c48c4Sopenharmony_ci { 159da0c48c4Sopenharmony_ci if (morememory (st, sizeof (struct Dwelf_Strent) + len)) 160da0c48c4Sopenharmony_ci return NULL; 161da0c48c4Sopenharmony_ci 162da0c48c4Sopenharmony_ci align = 0; 163da0c48c4Sopenharmony_ci } 164da0c48c4Sopenharmony_ci 165da0c48c4Sopenharmony_ci /* Create the reserved string. */ 166da0c48c4Sopenharmony_ci Dwelf_Strent *newstr = (Dwelf_Strent *) (st->backp + align); 167da0c48c4Sopenharmony_ci newstr->string = str; 168da0c48c4Sopenharmony_ci newstr->len = len; 169da0c48c4Sopenharmony_ci newstr->next = NULL; 170da0c48c4Sopenharmony_ci newstr->left = NULL; 171da0c48c4Sopenharmony_ci newstr->right = NULL; 172da0c48c4Sopenharmony_ci newstr->offset = 0; 173da0c48c4Sopenharmony_ci for (int i = len - 2; i >= 0; --i) 174da0c48c4Sopenharmony_ci newstr->reverse[i] = str[len - 2 - i]; 175da0c48c4Sopenharmony_ci newstr->reverse[len - 1] = '\0'; 176da0c48c4Sopenharmony_ci st->backp += align + sizeof (struct Dwelf_Strent) + len; 177da0c48c4Sopenharmony_ci st->left -= align + sizeof (struct Dwelf_Strent) + len; 178da0c48c4Sopenharmony_ci 179da0c48c4Sopenharmony_ci return newstr; 180da0c48c4Sopenharmony_ci} 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci 183da0c48c4Sopenharmony_ci/* XXX This function should definitely be rewritten to use a balancing 184da0c48c4Sopenharmony_ci tree algorithm (AVL, red-black trees). For now a simple, correct 185da0c48c4Sopenharmony_ci implementation is enough. */ 186da0c48c4Sopenharmony_cistatic Dwelf_Strent ** 187da0c48c4Sopenharmony_cisearchstring (Dwelf_Strent **sep, Dwelf_Strent *newstr) 188da0c48c4Sopenharmony_ci{ 189da0c48c4Sopenharmony_ci /* More strings? */ 190da0c48c4Sopenharmony_ci if (*sep == NULL) 191da0c48c4Sopenharmony_ci { 192da0c48c4Sopenharmony_ci *sep = newstr; 193da0c48c4Sopenharmony_ci return sep; 194da0c48c4Sopenharmony_ci } 195da0c48c4Sopenharmony_ci 196da0c48c4Sopenharmony_ci /* Compare the strings. */ 197da0c48c4Sopenharmony_ci int cmpres = memcmp ((*sep)->reverse, newstr->reverse, 198da0c48c4Sopenharmony_ci MIN ((*sep)->len, newstr->len) - 1); 199da0c48c4Sopenharmony_ci if (cmpres == 0) 200da0c48c4Sopenharmony_ci /* We found a matching string. */ 201da0c48c4Sopenharmony_ci return sep; 202da0c48c4Sopenharmony_ci else if (cmpres > 0) 203da0c48c4Sopenharmony_ci return searchstring (&(*sep)->left, newstr); 204da0c48c4Sopenharmony_ci else 205da0c48c4Sopenharmony_ci return searchstring (&(*sep)->right, newstr); 206da0c48c4Sopenharmony_ci} 207da0c48c4Sopenharmony_ci 208da0c48c4Sopenharmony_ci 209da0c48c4Sopenharmony_ci/* Add new string. The actual string is assumed to be permanent. */ 210da0c48c4Sopenharmony_cistatic Dwelf_Strent * 211da0c48c4Sopenharmony_cistrtab_add (Dwelf_Strtab *st, const char *str, size_t len) 212da0c48c4Sopenharmony_ci{ 213da0c48c4Sopenharmony_ci /* Make sure all "" strings get offset 0 but only if the table was 214da0c48c4Sopenharmony_ci created with a special null entry in mind. */ 215da0c48c4Sopenharmony_ci if (len == 1 && st->null.string != NULL) 216da0c48c4Sopenharmony_ci return &st->null; 217da0c48c4Sopenharmony_ci 218da0c48c4Sopenharmony_ci /* Allocate memory for the new string and its associated information. */ 219da0c48c4Sopenharmony_ci Dwelf_Strent *newstr = newstring (st, str, len); 220da0c48c4Sopenharmony_ci if (newstr == NULL) 221da0c48c4Sopenharmony_ci return NULL; 222da0c48c4Sopenharmony_ci 223da0c48c4Sopenharmony_ci /* Search in the array for the place to insert the string. If there 224da0c48c4Sopenharmony_ci is no string with matching prefix and no string with matching 225da0c48c4Sopenharmony_ci leading substring, create a new entry. */ 226da0c48c4Sopenharmony_ci Dwelf_Strent **sep = searchstring (&st->root, newstr); 227da0c48c4Sopenharmony_ci if (*sep != newstr) 228da0c48c4Sopenharmony_ci { 229da0c48c4Sopenharmony_ci /* This is not the same entry. This means we have a prefix match. */ 230da0c48c4Sopenharmony_ci if ((*sep)->len > newstr->len) 231da0c48c4Sopenharmony_ci { 232da0c48c4Sopenharmony_ci /* Check whether we already know this string. */ 233da0c48c4Sopenharmony_ci for (Dwelf_Strent *subs = (*sep)->next; subs != NULL; 234da0c48c4Sopenharmony_ci subs = subs->next) 235da0c48c4Sopenharmony_ci if (subs->len == newstr->len) 236da0c48c4Sopenharmony_ci { 237da0c48c4Sopenharmony_ci /* We have an exact match with a substring. Free the memory 238da0c48c4Sopenharmony_ci we allocated. */ 239da0c48c4Sopenharmony_ci st->left += st->backp - (char *) newstr; 240da0c48c4Sopenharmony_ci st->backp = (char *) newstr; 241da0c48c4Sopenharmony_ci 242da0c48c4Sopenharmony_ci return subs; 243da0c48c4Sopenharmony_ci } 244da0c48c4Sopenharmony_ci 245da0c48c4Sopenharmony_ci /* We have a new substring. This means we don't need the reverse 246da0c48c4Sopenharmony_ci string of this entry anymore. */ 247da0c48c4Sopenharmony_ci st->backp -= newstr->len; 248da0c48c4Sopenharmony_ci st->left += newstr->len; 249da0c48c4Sopenharmony_ci 250da0c48c4Sopenharmony_ci newstr->next = (*sep)->next; 251da0c48c4Sopenharmony_ci (*sep)->next = newstr; 252da0c48c4Sopenharmony_ci } 253da0c48c4Sopenharmony_ci else if ((*sep)->len != newstr->len) 254da0c48c4Sopenharmony_ci { 255da0c48c4Sopenharmony_ci /* When we get here it means that the string we are about to 256da0c48c4Sopenharmony_ci add has a common prefix with a string we already have but 257da0c48c4Sopenharmony_ci it is longer. In this case we have to put it first. */ 258da0c48c4Sopenharmony_ci st->total += newstr->len - (*sep)->len; 259da0c48c4Sopenharmony_ci newstr->next = *sep; 260da0c48c4Sopenharmony_ci newstr->left = (*sep)->left; 261da0c48c4Sopenharmony_ci newstr->right = (*sep)->right; 262da0c48c4Sopenharmony_ci *sep = newstr; 263da0c48c4Sopenharmony_ci } 264da0c48c4Sopenharmony_ci else 265da0c48c4Sopenharmony_ci { 266da0c48c4Sopenharmony_ci /* We have an exact match. Free the memory we allocated. */ 267da0c48c4Sopenharmony_ci st->left += st->backp - (char *) newstr; 268da0c48c4Sopenharmony_ci st->backp = (char *) newstr; 269da0c48c4Sopenharmony_ci 270da0c48c4Sopenharmony_ci newstr = *sep; 271da0c48c4Sopenharmony_ci } 272da0c48c4Sopenharmony_ci } 273da0c48c4Sopenharmony_ci else 274da0c48c4Sopenharmony_ci st->total += newstr->len; 275da0c48c4Sopenharmony_ci 276da0c48c4Sopenharmony_ci return newstr; 277da0c48c4Sopenharmony_ci} 278da0c48c4Sopenharmony_ci 279da0c48c4Sopenharmony_ciDwelf_Strent * 280da0c48c4Sopenharmony_cidwelf_strtab_add (Dwelf_Strtab *st, const char *str) 281da0c48c4Sopenharmony_ci{ 282da0c48c4Sopenharmony_ci return strtab_add (st, str, strlen (str) + 1); 283da0c48c4Sopenharmony_ci} 284da0c48c4Sopenharmony_ci 285da0c48c4Sopenharmony_ciDwelf_Strent * 286da0c48c4Sopenharmony_cidwelf_strtab_add_len (Dwelf_Strtab *st, const char *str, size_t len) 287da0c48c4Sopenharmony_ci{ 288da0c48c4Sopenharmony_ci return strtab_add (st, str, len); 289da0c48c4Sopenharmony_ci} 290da0c48c4Sopenharmony_ci 291da0c48c4Sopenharmony_cistatic void 292da0c48c4Sopenharmony_cicopystrings (Dwelf_Strent *nodep, char **freep, size_t *offsetp) 293da0c48c4Sopenharmony_ci{ 294da0c48c4Sopenharmony_ci if (nodep->left != NULL) 295da0c48c4Sopenharmony_ci copystrings (nodep->left, freep, offsetp); 296da0c48c4Sopenharmony_ci 297da0c48c4Sopenharmony_ci /* Process the current node. */ 298da0c48c4Sopenharmony_ci nodep->offset = *offsetp; 299da0c48c4Sopenharmony_ci *freep = (char *) mempcpy (*freep, nodep->string, nodep->len); 300da0c48c4Sopenharmony_ci *offsetp += nodep->len; 301da0c48c4Sopenharmony_ci 302da0c48c4Sopenharmony_ci for (Dwelf_Strent *subs = nodep->next; subs != NULL; subs = subs->next) 303da0c48c4Sopenharmony_ci { 304da0c48c4Sopenharmony_ci assert (subs->len < nodep->len); 305da0c48c4Sopenharmony_ci subs->offset = nodep->offset + nodep->len - subs->len; 306da0c48c4Sopenharmony_ci assert (subs->offset != 0 || subs->string[0] == '\0'); 307da0c48c4Sopenharmony_ci } 308da0c48c4Sopenharmony_ci 309da0c48c4Sopenharmony_ci if (nodep->right != NULL) 310da0c48c4Sopenharmony_ci copystrings (nodep->right, freep, offsetp); 311da0c48c4Sopenharmony_ci} 312da0c48c4Sopenharmony_ci 313da0c48c4Sopenharmony_ci 314da0c48c4Sopenharmony_ciElf_Data * 315da0c48c4Sopenharmony_cidwelf_strtab_finalize (Dwelf_Strtab *st, Elf_Data *data) 316da0c48c4Sopenharmony_ci{ 317da0c48c4Sopenharmony_ci size_t nulllen = st->nullstr ? 1 : 0; 318da0c48c4Sopenharmony_ci 319da0c48c4Sopenharmony_ci /* Fill in the information. */ 320da0c48c4Sopenharmony_ci data->d_buf = malloc (st->total + nulllen); 321da0c48c4Sopenharmony_ci if (data->d_buf == NULL) 322da0c48c4Sopenharmony_ci return NULL; 323da0c48c4Sopenharmony_ci 324da0c48c4Sopenharmony_ci /* The first byte must always be zero if we created the table with a 325da0c48c4Sopenharmony_ci null string. */ 326da0c48c4Sopenharmony_ci if (st->nullstr) 327da0c48c4Sopenharmony_ci *((char *) data->d_buf) = '\0'; 328da0c48c4Sopenharmony_ci 329da0c48c4Sopenharmony_ci data->d_type = ELF_T_BYTE; 330da0c48c4Sopenharmony_ci data->d_size = st->total + nulllen; 331da0c48c4Sopenharmony_ci data->d_off = 0; 332da0c48c4Sopenharmony_ci data->d_align = 1; 333da0c48c4Sopenharmony_ci data->d_version = EV_CURRENT; 334da0c48c4Sopenharmony_ci 335da0c48c4Sopenharmony_ci /* Now run through the tree and add all the string while also updating 336da0c48c4Sopenharmony_ci the offset members of the elfstrent records. */ 337da0c48c4Sopenharmony_ci char *endp = (char *) data->d_buf + nulllen; 338da0c48c4Sopenharmony_ci size_t copylen = nulllen; 339da0c48c4Sopenharmony_ci if (st->root) 340da0c48c4Sopenharmony_ci copystrings (st->root, &endp, ©len); 341da0c48c4Sopenharmony_ci assert (copylen == st->total + nulllen); 342da0c48c4Sopenharmony_ci 343da0c48c4Sopenharmony_ci return data; 344da0c48c4Sopenharmony_ci} 345da0c48c4Sopenharmony_ci 346da0c48c4Sopenharmony_ci 347da0c48c4Sopenharmony_cisize_t 348da0c48c4Sopenharmony_cidwelf_strent_off (Dwelf_Strent *se) 349da0c48c4Sopenharmony_ci{ 350da0c48c4Sopenharmony_ci return se->offset; 351da0c48c4Sopenharmony_ci} 352da0c48c4Sopenharmony_ci 353da0c48c4Sopenharmony_ci 354da0c48c4Sopenharmony_ciconst char * 355da0c48c4Sopenharmony_cidwelf_strent_str (Dwelf_Strent *se) 356da0c48c4Sopenharmony_ci{ 357da0c48c4Sopenharmony_ci return se->string; 358da0c48c4Sopenharmony_ci} 359