1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 */ 31 32 /* 33 * Utility functions 34 */ 35 #include <unistd.h> 36 #include <stdio.h> 37 #include <stdarg.h> 38 #include <string.h> 39 #include <fcntl.h> 40 #include <sys/types.h> 41 #include <sys/mman.h> 42 #include <errno.h> 43 #include <sgs.h> 44 #include <libintl.h> 45 #include <debug.h> 46 #include "msg.h" 47 #include "_libld.h" 48 49 /* 50 * libld_malloc() and dz_map() are used for both performance and for ease of 51 * programming: 52 * 53 * Performance: 54 * The link-edit is a short lived process which doesn't really free much 55 * of the dynamic memory that it requests. Because of this, it is more 56 * important to optimize for quick memory allocations than the 57 * re-usability of the memory. 58 * 59 * By also mmaping blocks of pages in from /dev/zero we don't need to 60 * waste the overhead of zeroing out these pages for calloc() requests. 61 * 62 * Memory Management: 63 * By doing all libld memory management through the ld_malloc routine 64 * it's much easier to free up all memory at the end by simply unmaping 65 * all of the blocks that were mapped in through dz_map(). This is much 66 * simpler then trying to track all of the libld structures that were 67 * dynamically allocate and are actually pointers into the ELF files. 68 * 69 * It's important that we can free up all of our dynamic memory because 70 * libld is used by ld.so.1 when it performs dlopen()'s of relocatable 71 * objects. 72 * 73 * Format: 74 * The memory blocks for each allocation store the size of the allocation 75 * in the first 8 bytes of the block. The pointer that is returned by 76 * libld_malloc() is actually the address of (block + 8): 77 * 78 * (addr - 8) block_size 79 * (addr) <allocated block> 80 * 81 * The size is retained in order to implement realloc(), and to perform 82 * the required memcpy(). 8 bytes are uses, as the memory area returned 83 * by libld_malloc() must be 8 byte-aligned. Even in a 32-bit environment, 84 * u_longlog_t pointers are employed. 85 * 86 * Map anonymous memory via MAP_ANON (added in Solaris 8). 87 */ 88 static void * 89 dz_map(size_t size) 90 { 91 void *addr; 92 93 if ((addr = mmap(0, size, (PROT_READ | PROT_WRITE | PROT_EXEC), 94 (MAP_PRIVATE | MAP_ANON), -1, 0)) == MAP_FAILED) { 95 int err = errno; 96 eprintf(0, ERR_FATAL, MSG_INTL(MSG_SYS_MMAPANON), 97 strerror(err)); 98 return (MAP_FAILED); 99 } 100 return (addr); 101 } 102 103 void * 104 libld_malloc(size_t size) 105 { 106 Ld_heap *chp = ld_heap; 107 void *vptr; 108 size_t asize = size + HEAPALIGN; 109 110 /* 111 * If this is the first allocation, or the allocation request is greater 112 * than the current free space available, allocate a new heap. 113 */ 114 if ((chp == 0) || 115 (((size_t)chp->lh_end - (size_t)chp->lh_free) <= asize)) { 116 Ld_heap *nhp; 117 size_t hsize = (size_t)S_ROUND(sizeof (Ld_heap), HEAPALIGN); 118 size_t tsize = (size_t)S_ROUND((asize + hsize), HEAPALIGN); 119 120 /* 121 * Allocate a block that is at minimum 'HEAPBLOCK' size 122 */ 123 if (tsize < HEAPBLOCK) 124 tsize = HEAPBLOCK; 125 126 if ((nhp = dz_map(tsize)) == MAP_FAILED) 127 return (NULL); 128 129 nhp->lh_next = chp; 130 nhp->lh_free = (void *)((size_t)nhp + hsize); 131 nhp->lh_end = (void *)((size_t)nhp + tsize); 132 133 ld_heap = chp = nhp; 134 } 135 vptr = chp->lh_free; 136 137 /* 138 * Assign size to head of allocated block (used by realloc), and 139 * memory arena as then next 8-byte aligned offset. 140 */ 141 *((size_t *)vptr) = size; 142 vptr = (void *)((size_t)vptr + HEAPALIGN); 143 144 /* 145 * Increment free to point to next available block 146 */ 147 chp->lh_free = (void *)S_ROUND((size_t)chp->lh_free + asize, 148 HEAPALIGN); 149 150 return (vptr); 151 } 152 153 void * 154 libld_realloc(void *ptr, size_t size) 155 { 156 size_t psize; 157 void *vptr; 158 159 if (ptr == NULL) 160 return (libld_malloc(size)); 161 162 /* 163 * Size of the allocated blocks is stored *just* before the blocks 164 * address. 165 */ 166 psize = *((size_t *)((size_t)ptr - HEAPALIGN)); 167 168 /* 169 * If the block actually fits then just return. 170 */ 171 if (size <= psize) 172 return (ptr); 173 174 if ((vptr = libld_malloc(size)) != 0) 175 (void) memcpy(vptr, ptr, psize); 176 177 return (vptr); 178 } 179 180 void 181 /* ARGSUSED 0 */ 182 libld_free(void *ptr) 183 { 184 } 185 186 /* 187 * Append an item to the specified list, and return a pointer to the list 188 * node created. 189 */ 190 Listnode * 191 list_appendc(List *lst, const void *item) 192 { 193 Listnode *_lnp; 194 195 if ((_lnp = libld_malloc(sizeof (Listnode))) == NULL) 196 return (NULL); 197 198 _lnp->data = (void *)item; 199 _lnp->next = NULL; 200 201 if (lst->head == NULL) 202 lst->tail = lst->head = _lnp; 203 else { 204 lst->tail->next = _lnp; 205 lst->tail = lst->tail->next; 206 } 207 return (_lnp); 208 } 209 210 /* 211 * Add an item after the specified listnode, and return a pointer to the list 212 * node created. 213 */ 214 Listnode * 215 list_insertc(List *lst, const void *item, Listnode *lnp) 216 { 217 Listnode *_lnp; 218 219 if ((_lnp = libld_malloc(sizeof (Listnode))) == NULL) 220 return (NULL); 221 222 _lnp->data = (void *)item; 223 _lnp->next = lnp->next; 224 if (_lnp->next == NULL) 225 lst->tail = _lnp; 226 lnp->next = _lnp; 227 return (_lnp); 228 } 229 230 /* 231 * Prepend an item to the specified list, and return a pointer to the 232 * list node created. 233 */ 234 Listnode * 235 list_prependc(List *lst, const void *item) 236 { 237 Listnode *_lnp; 238 239 if ((_lnp = libld_malloc(sizeof (Listnode))) == NULL) 240 return (NULL); 241 242 _lnp->data = (void *)item; 243 244 if (lst->head == NULL) { 245 _lnp->next = NULL; 246 lst->tail = lst->head = _lnp; 247 } else { 248 _lnp->next = lst->head; 249 lst->head = _lnp; 250 } 251 return (_lnp); 252 } 253 254 /* 255 * Find out where to insert the node for reordering. List of insect structures 256 * is traversed and the is_txtndx field of the insect structure is examined 257 * and that determines where the new input section should be inserted. 258 * All input sections which have a non zero is_txtndx value will be placed 259 * in ascending order before sections with zero is_txtndx value. This 260 * implies that any section that does not appear in the map file will be 261 * placed at the end of this list as it will have a is_txtndx value of 0. 262 * Returns: NULL if the input section should be inserted at beginning 263 * of list else A pointer to the entry AFTER which this new section should 264 * be inserted. 265 */ 266 Listnode * 267 list_where(List *lst, Word num) 268 { 269 Listnode *ln, *pln; /* Temp list node ptr */ 270 Is_desc *isp; /* Temp Insect structure */ 271 Word n; 272 273 /* 274 * No input sections exist, so add at beginning of list 275 */ 276 if (lst->head == NULL) 277 return (NULL); 278 279 for (ln = lst->head, pln = ln; ln != NULL; pln = ln, ln = ln->next) { 280 isp = (Is_desc *)ln->data; 281 /* 282 * This should never happen, but if it should we 283 * try to do the right thing. Insert at the 284 * beginning of list if no other items exist, else 285 * end of already existing list, prior to this null 286 * item. 287 */ 288 if (isp == NULL) { 289 if (ln == pln) { 290 return (NULL); 291 } else { 292 return (pln); 293 } 294 } 295 /* 296 * We have reached end of reorderable items. All 297 * following items have is_txtndx values of zero 298 * So insert at end of reorderable items. 299 */ 300 if ((n = isp->is_txtndx) > num || n == 0) { 301 if (ln == pln) { 302 return (NULL); 303 } else { 304 return (pln); 305 } 306 } 307 /* 308 * We have reached end of list, so insert 309 * at the end of this list. 310 */ 311 if ((n != 0) && (ln->next == NULL)) 312 return (ln); 313 } 314 return (NULL); 315 } 316 317 /* 318 * Determine if a shared object definition structure already exists and if 319 * not create one. These definitions provide for recording information 320 * regarding shared objects that are still to be processed. Once processed 321 * shared objects are maintained on the ofl_sos list. The information 322 * recorded in this structure includes: 323 * 324 * o DT_USED requirements. In these cases definitions are added during 325 * mapfile processing of `-' entries (see map_dash()). 326 * 327 * o implicit NEEDED entries. As shared objects are processed from the 328 * command line so any of their dependencies are recorded in these 329 * structures for later processing (see process_dynamic()). 330 * 331 * o version requirements. Any explicit shared objects that have version 332 * dependencies on other objects have their version requirements recorded. 333 * In these cases definitions are added during mapfile processing of `-' 334 * entries (see map_dash()). Also, shared objects may have versioning 335 * requirements on their NEEDED entries. These cases are added during 336 * their version processing (see vers_need_process()). 337 * 338 * Note: Both process_dynamic() and vers_need_process() may generate the 339 * initial version definition structure because you can't rely on what 340 * section (.dynamic or .SUNW_version) may be processed first from any 341 * input file. 342 */ 343 Sdf_desc * 344 sdf_find(const char *name, List *lst) 345 { 346 Listnode *lnp; 347 Sdf_desc *sdf; 348 349 for (LIST_TRAVERSE(lst, lnp, sdf)) 350 if (strcmp(name, sdf->sdf_name) == 0) 351 return (sdf); 352 353 return (NULL); 354 } 355 356 Sdf_desc * 357 sdf_add(const char *name, List *lst) 358 { 359 Sdf_desc *sdf; 360 361 if (!(sdf = libld_calloc(sizeof (Sdf_desc), 1))) 362 return ((Sdf_desc *)S_ERROR); 363 364 sdf->sdf_name = name; 365 366 if (list_appendc(lst, sdf) == 0) 367 return ((Sdf_desc *)S_ERROR); 368 else 369 return (sdf); 370 } 371 372 /* 373 * Add a string, separated by a colon, to an existing string. Typically used 374 * to maintain filter, rpath and audit names, of which there is normally only 375 * one string supplied anyway. 376 */ 377 char * 378 add_string(char *old, char *str) 379 { 380 char *new; 381 382 if (old) { 383 char *_str; 384 size_t len; 385 386 /* 387 * If an original string exists, make sure this new string 388 * doesn't get duplicated. 389 */ 390 if ((_str = strstr(old, str)) != NULL) { 391 if (((_str == old) || 392 (*(_str - 1) == *(MSG_ORIG(MSG_STR_COLON)))) && 393 (_str += strlen(str)) && 394 ((*_str == '\0') || 395 (*_str == *(MSG_ORIG(MSG_STR_COLON))))) 396 return (old); 397 } 398 399 len = strlen(old) + strlen(str) + 2; 400 if ((new = libld_calloc(1, len)) == NULL) 401 return ((char *)S_ERROR); 402 (void) snprintf(new, len, MSG_ORIG(MSG_FMT_COLPATH), old, str); 403 } else { 404 if ((new = libld_malloc(strlen(str) + 1)) == NULL) 405 return ((char *)S_ERROR); 406 (void) strcpy(new, str); 407 } 408 409 return (new); 410 } 411 412 /* 413 * Messaging support - funnel everything through dgettext(). 414 */ 415 416 const char * 417 _libld_msg(Msg mid) 418 { 419 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 420 } 421 422 /* 423 * Determine whether a symbol name should be demangled. 424 */ 425 const char * 426 demangle(const char *name) 427 { 428 if (demangle_flag) 429 return (Elf_demangle_name(name)); 430 else 431 return (name); 432 } 433