1/* 2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#ifdef SHLIB 24#include "shlib.h" 25#endif /* SHLIB */ 26/* 27 * This file contains the routines that deal with literal 'C' string sections. 28 * A string in this section must beable to me moved freely with respect to other 29 * strings or data. This means relocation must not reach outside the string and 30 * things like: "abc"[i+20] can't be in this type of section. Also strings 31 * like: "foo\0bar" can not be in this type of section. 32 */ 33#include <stdlib.h> 34#if !(defined(KLD) && defined(__STATIC__)) 35#include <stdio.h> 36#include <limits.h> 37#include <mach/mach.h> 38#else /* defined(KLD) && defined(__STATIC__) */ 39#include <mach/mach.h> 40#include <mach/kern_return.h> 41#define CHAR_MAX 0xff 42#endif /* !(defined(KLD) && defined(__STATIC__)) */ 43#include <stdarg.h> 44#include <string.h> 45#include "stuff/openstep_mach.h" 46#include <mach-o/loader.h> 47#include "stuff/bool.h" 48#include "stuff/bytesex.h" 49 50#include "ld.h" 51#include "live_refs.h" 52#include "objects.h" 53#include "sections.h" 54#include "cstring_literals.h" 55#include "pass2.h" 56#include "hash_string.h" 57#include "symbols.h" 58 59/* 60 * cstring_merge() merges cstring literals from the specified section in the 61 * current object file (cur_obj). When redo_live is FALSE it allocates a fine 62 * relocation map and sets the fine_relocs field in the section_map to it (as 63 * well as the count). When redo_live is TRUE it re-merges only the live 64 * cstrings based on the live bit in the previouly allocated fine_relocs. 65 */ 66__private_extern__ 67void 68cstring_merge( 69struct cstring_data *data, 70struct merged_section *ms, 71struct section *s, 72struct section_map *section_map, 73enum bool redo_live) 74{ 75 unsigned long ncstrings, i; 76 char *cstrings, *p; 77 struct fine_reloc *fine_relocs; 78 79 if(s->size == 0){ 80 if(redo_live == FALSE){ 81 section_map->fine_relocs = NULL; 82 section_map->nfine_relocs = 0; 83 } 84 return; 85 } 86 /* 87 * Count the number of strings so the size of the fine relocation 88 * structures can be allocated. 89 */ 90 ncstrings = 0; 91 cstrings = cur_obj->obj_addr + s->offset; 92 if(*(cstrings + s->size - 1) != '\0'){ 93 error_with_cur_obj("literal C string section (%.16s,%.16s) does " 94 "not end with a '\\0'", s->segname, s->sectname); 95 return; 96 } 97 for(p = cstrings; p < cstrings + s->size; p += strlen(p) + 1) 98 ncstrings++; 99#ifdef DEBUG 100 if(redo_live == FALSE){ 101 data->nfiles++; 102 data->nbytes += s->size; 103 data->ninput_strings += ncstrings; 104 } 105#endif /* DEBUG */ 106 107 /* 108 * We will be called the first time with redo_live == FALSE and will 109 * just merge the cstrings from the input file and create the 110 * fine_relocs. 111 */ 112 if(redo_live == FALSE){ 113 fine_relocs = allocate(ncstrings * sizeof(struct fine_reloc)); 114 memset(fine_relocs, '\0', ncstrings * sizeof(struct fine_reloc)); 115 116 /* 117 * lookup and enter each C string in the section and record the 118 * offsets in the input file and in the output file. 119 */ 120 p = cstrings; 121 for(i = 0; i < ncstrings; i++){ 122 fine_relocs[i].input_offset = p - cstrings; 123 fine_relocs[i].output_offset = lookup_cstring(p, data, ms); 124 p += strlen(p) + 1; 125 } 126 section_map->fine_relocs = fine_relocs; 127 section_map->nfine_relocs = ncstrings; 128 } 129 else{ 130 /* 131 * redo_live == TRUE and this is being called a second time after 132 * all the cstrings were previouly merged when -dead_strip is 133 * specified. So now we walk the fine_relocs and only re-merge the 134 * live strings. 135 */ 136 fine_relocs = section_map->fine_relocs; 137 ncstrings = section_map->nfine_relocs; 138 p = cstrings; 139 for(i = 0; i < ncstrings; i++){ 140 if(fine_relocs[i].live == TRUE){ 141 fine_relocs[i].output_offset = lookup_cstring(p, data, ms); 142 } 143 else{ 144 fine_relocs[i].output_offset = 0; 145 } 146 p += strlen(p) + 1; 147 } 148 } 149} 150 151/* 152 * cstring_order() enters cstring literals from the order_file from the merged 153 * section structure. Since this is called before any call to cstring_merge 154 * and it enters the strings in the order of the file it causes the section 155 * to be ordered. 156 */ 157__private_extern__ 158void 159cstring_order( 160struct cstring_data *data, 161struct merged_section *ms) 162{ 163#ifndef RLD 164 unsigned long i, line_number, line_length, max_line_length, output_offset; 165 char *buffer; 166 kern_return_t r; 167 struct cstring_order_line *cstring_order_lines; 168 169 /* 170 * Parse the load order file by changing '\n' to '\0'. Also check for 171 * '\0 in the file and flag them as errors. Also determine the maximum 172 * line length of the file for the needed buffer to allocate for 173 * character translation. 174 */ 175 line_number = 1; 176 line_length = 1; 177 max_line_length = 1; 178 for(i = 0; i < ms->order_size; i++){ 179 if(ms->order_addr[i] == '\0'){ 180 fatal("format error in -sectorder file: %s line %lu character " 181 "possition %lu for section (%.16s,%.16s) (illegal null " 182 "character \'\\0\' found)", ms->order_filename, 183 line_number, line_length, ms->s.segname, ms->s.sectname); 184 } 185 if(ms->order_addr[i] == '\n'){ 186 ms->order_addr[i] = '\0'; 187 if(line_length > max_line_length) 188 max_line_length = line_length; 189 line_number++; 190 line_length = 1; 191 } 192 else 193 line_length++; 194 } 195 196 /* 197 * Allocate the buffer to translate the order file lines' escape 198 * characters into real characters. 199 */ 200 buffer = allocate(max_line_length + 1); 201 202 /* 203 * If -dead_strip is specified allocate the needed structures so that 204 * the order of the live cstrings can be recreated later by 205 * cstring_reset_live(). 206 */ 207 cstring_order_lines = NULL; 208 if(dead_strip == TRUE){ 209 data->cstring_load_order_data = 210 allocate(sizeof(struct cstring_load_order_data)); 211 cstring_order_lines = allocate(sizeof(struct cstring_order_line) * 212 (line_number - 1)); 213 data->cstring_load_order_data->order_line_buffer = 214 buffer; 215 data->cstring_load_order_data->cstring_order_lines = 216 cstring_order_lines; 217 data->cstring_load_order_data->ncstring_order_lines = 218 (line_number - 1); 219 } 220 221 /* 222 * Process each line in the order file by translating all escape 223 * characters and then entering the cstring using lookup_cstring(). 224 * If -dead_strip is specified save away the starting character index 225 * of each order line and the output offset. 226 */ 227 line_number = 1; 228 for(i = 0; i < ms->order_size; i++){ 229 if(dead_strip == TRUE) 230 cstring_order_lines[line_number - 1].character_index = i; 231 232 get_cstring_from_sectorder(ms, &i, buffer, line_number, 1); 233 output_offset = lookup_cstring(buffer, data, ms); 234 235 if(dead_strip == TRUE) 236 cstring_order_lines[line_number - 1].output_offset = 237 output_offset; 238 239 line_number++; 240 } 241 242 /* 243 * If -dead_strip is not specified free up the memory for the line 244 * buffer and the load order file. If -dead_strip is specified these 245 * will be free'ed up in cstring_reset_live(). 246 */ 247 if(dead_strip == FALSE){ 248 249 /* deallocate the line buffer */ 250 free(buffer); 251 252 /* 253 * Deallocate the memory for the load order file now that it is 254 * nolonger needed (since the memory has been written on it is 255 * always deallocated so it won't get written to the swap file 256 * unnecessarily). 257 */ 258 if((r = vm_deallocate(mach_task_self(), (vm_address_t) 259 ms->order_addr, ms->order_size)) != KERN_SUCCESS) 260 mach_fatal(r, "can't vm_deallocate() memory for -sectorder " 261 "file: %s for section (%.16s,%.16s)", 262 ms->order_filename, ms->s.segname, 263 ms->s.sectname); 264 ms->order_addr = NULL; 265 } 266#endif /* !defined(RLD) */ 267} 268 269/* 270 * cstring_reset_live() is called when -dead_strip is specified after all the 271 * literals from the input objects are merged. It clears out the cstring_data 272 * so the live cstrings can be re-merged (by later calling cstring_merge() with 273 * redo_live == TRUE. In here we first merge in the live cstrings from the 274 * order file if any. 275 */ 276__private_extern__ 277void 278cstring_reset_live( 279struct cstring_data *data, 280struct merged_section *ms) 281{ 282#ifndef RLD 283 unsigned long i, ncstring_order_lines, character_index, line_number; 284 char *buffer; 285 struct cstring_order_line *cstring_order_lines; 286 enum bool live; 287 kern_return_t r; 288 289 /* reset the merge section size back to zero */ 290 ms->s.size = 0; 291 292 /* clear out the previously merged data */ 293 cstring_free(data); 294 295 /* 296 * If this merged section has an order file we need to re-merged only 297 * the live cstrings from that order file. 298 */ 299 if(ms->order_filename != NULL){ 300 buffer = data->cstring_load_order_data->order_line_buffer; 301 cstring_order_lines = 302 data->cstring_load_order_data->cstring_order_lines; 303 ncstring_order_lines = 304 data->cstring_load_order_data->ncstring_order_lines; 305 for(i = 0; i < ncstring_order_lines; i++){ 306 /* 307 * Figure out if this cstring order line's output_index is live 308 * and if so re-merge the cstring literal. 309 */ 310 live = is_literal_output_offset_live( 311 ms, cstring_order_lines[i].output_offset); 312 line_number = i + 1; 313 if(live){ 314 character_index = cstring_order_lines[i].character_index; 315 get_cstring_from_sectorder(ms, &character_index, buffer, 316 line_number, 1); 317 (void)lookup_cstring(buffer, data, ms); 318 } 319 else{ 320 if(sectorder_detail == TRUE) 321 warning("specification of string in -sectorder file: " 322 "%s on line %lu for section (%.16s,%.16s) not " 323 "used (dead stripped)", ms->order_filename, 324 line_number, ms->s.segname, ms->s.sectname); 325 } 326 } 327 328 /* deallocate the various data structures no longer needed */ 329 free(data->cstring_load_order_data->order_line_buffer); 330 free(data->cstring_load_order_data->cstring_order_lines); 331 free(data->cstring_load_order_data); 332 data->cstring_load_order_data = NULL; 333 334 /* 335 * Deallocate the memory for the load order file now that it is 336 * nolonger needed (since the memory has been written on it is 337 * allways deallocated so it won't get written to the swap file 338 * unnecessarily). 339 */ 340 if((r = vm_deallocate(mach_task_self(), (vm_address_t) 341 ms->order_addr, ms->order_size)) != KERN_SUCCESS) 342 mach_fatal(r, "can't vm_deallocate() memory for -sectorder " 343 "file: %s for section (%.16s,%.16s)", 344 ms->order_filename, ms->s.segname, 345 ms->s.sectname); 346 ms->order_addr = NULL; 347 } 348#endif /* !defined(RLD) */ 349} 350 351/* 352 * get_cstring_from_sectorder() parses a cstring from a order file for the 353 * specified merged_section, ms, starting from the index, *index the order file 354 * must have had its newlines changed to '\0's previouly. It places the parsed 355 * cstring in the specified buffer, buffer and advances the index over the 356 * cstring it parsed. line_number and char_pos are used for printing error 357 * messages and refer the line_number and character possition the index is at. 358 */ 359__private_extern__ 360void 361get_cstring_from_sectorder( 362struct merged_section *ms, 363unsigned long *index, 364char *buffer, 365unsigned long line_number, 366unsigned long char_pos) 367{ 368#ifndef RLD 369 unsigned long i, j, k, char_value; 370 char octal[4], hex[9]; 371 372 j = 0; 373 /* 374 * See that this is not the end of a line in the order file. 375 */ 376 for(i = *index; i < ms->order_size && ms->order_addr[i] != '\0'; i++){ 377 /* 378 * See if this character the start of an escape sequence. 379 */ 380 if(ms->order_addr[i] == '\\'){ 381 if(i + 1 >= ms->order_size || ms->order_addr[i + 1] == '\0') 382 fatal("format error in -sectorder file: %s line %lu " 383 "character possition %lu for section (%.16s," 384 "%.16s) (\'\\\' at the end of the line)", 385 ms->order_filename, line_number, char_pos, 386 ms->s.segname, ms->s.sectname); 387 /* move past the '\\' */ 388 i++; 389 char_pos++; 390 if(ms->order_addr[i] >= '0' && ms->order_addr[i] <= '7'){ 391 /* 1, 2 or 3 octal digits */ 392 k = 0; 393 octal[k++] = ms->order_addr[i]; 394 char_pos++; 395 if(i+1 < ms->order_size && 396 ms->order_addr[i+1] >= '0' && 397 ms->order_addr[i+1] <= '7'){ 398 octal[k++] = ms->order_addr[++i]; 399 char_pos++; 400 } 401 if(i+1 < ms->order_size && 402 ms->order_addr[i+1] >= '0' && 403 ms->order_addr[i+1] <= '7'){ 404 octal[k++] = ms->order_addr[++i]; 405 char_pos++; 406 } 407 octal[k] = '\0'; 408 char_value = strtol(octal, NULL, 8); 409 if(char_value > CHAR_MAX){ 410 error("format error in -sectorder file: %s line %lu " 411 "for section (%.16s,%.16s) (escape sequence" 412 " ending at character possition %lu out of " 413 "range for character)", ms->order_filename, 414 line_number, ms->s.segname, ms->s.sectname, 415 char_pos - 1); 416 } 417 buffer[j++] = (char)char_value; 418 } 419 else{ 420 switch(ms->order_addr[i]){ 421 case 'n': 422 buffer[j++] = '\n'; 423 char_pos++; 424 break; 425 case 't': 426 buffer[j++] = '\t'; 427 char_pos++; 428 break; 429 case 'v': 430 buffer[j++] = '\v'; 431 char_pos++; 432 break; 433 case 'b': 434 buffer[j++] = '\b'; 435 char_pos++; 436 break; 437 case 'r': 438 buffer[j++] = '\r'; 439 char_pos++; 440 break; 441 case 'f': 442 buffer[j++] = '\f'; 443 char_pos++; 444 break; 445 case 'a': 446 buffer[j++] = '\a'; 447 char_pos++; 448 break; 449 case '\\': 450 buffer[j++] = '\\'; 451 char_pos++; 452 break; 453 case '\?': 454 buffer[j++] = '\?'; 455 char_pos++; 456 break; 457 case '\'': 458 buffer[j++] = '\''; 459 char_pos++; 460 break; 461 case '\"': 462 buffer[j++] = '\"'; 463 char_pos++; 464 break; 465 case 'x': 466 /* hex digits */ 467 k = 0; 468 while(i+1 < ms->order_size && 469 ((ms->order_addr[i+1] >= '0' && 470 ms->order_addr[i+1] <= '9') || 471 (ms->order_addr[i+1] >= 'a' && 472 ms->order_addr[i+1] <= 'f') || 473 (ms->order_addr[i+1] >= 'A' && 474 ms->order_addr[i+1] <= 'F')) ){ 475 if(k <= 8) 476 hex[k++] = ms->order_addr[++i]; 477 else 478 ++i; 479 char_pos++; 480 } 481 if(k > 8){ 482 error("format error in -sectorder file: %s line" 483 " %lu for section (%.16s,%.16s) (hex " 484 "escape ending at character possition " 485 "%lu out of range)", ms->order_filename, 486 line_number, ms->s.segname, 487 ms->s.sectname, char_pos); 488 break; 489 } 490 hex[k] = '\0'; 491 char_value = strtol(hex, NULL, 16); 492 if(char_value > CHAR_MAX){ 493 error("format error in -sectorder file: %s line" 494 " %lu for section (%.16s,%.16s) (escape " 495 "sequence ending at character possition " 496 "%lu out of range for character)", 497 ms->order_filename, line_number, 498 ms->s.segname, ms->s.sectname, char_pos); 499 } 500 buffer[j++] = (char)char_value; 501 char_pos++; 502 break; 503 default: 504 error("format error in -sectorder file: %s line %lu " 505 "for section (%.16s,%.16s) (unknown escape " 506 "sequence ending at character possition %lu)", 507 ms->order_filename, line_number, 508 ms->s.segname, ms->s.sectname, char_pos); 509 buffer[j++] = ms->order_addr[i]; 510 char_pos++; 511 break; 512 } 513 } 514 } 515 /* 516 * This character is not the start of an escape sequence so take 517 * it as it is. 518 */ 519 else{ 520 buffer[j] = ms->order_addr[i]; 521 char_pos++; 522 j++; 523 } 524 } 525 buffer[j] = '\0'; 526 *index = i; 527#endif /* !defined(RLD) */ 528} 529 530/* 531 * lookup_cstring() looks up the cstring passed to it in the cstring_data 532 * passed to it and returns the offset the cstring will have in the output 533 * file. It creates the hash table as needed and the blocks to store the 534 * strings and attaches them to the cstring_data passed to it. The total 535 * size of the section is accumulated in ms->s.size which is the merged 536 * section for this literal section. The string is aligned to the alignment 537 * in the merged section (ms->s.align). 538 */ 539__private_extern__ 540unsigned long 541lookup_cstring( 542char *cstring, 543struct cstring_data *data, 544struct merged_section *ms) 545{ 546 unsigned long hashval, len, cstring_len; 547 struct cstring_bucket *bp; 548 struct cstring_block **p, *cstring_block; 549 550 if(data->hashtable == NULL){ 551 data->hashtable = allocate(sizeof(struct cstring_bucket *) * 552 CSTRING_HASHSIZE); 553 memset(data->hashtable, '\0', sizeof(struct cstring_bucket *) * 554 CSTRING_HASHSIZE); 555 } 556#if defined(DEBUG) && defined(PROBE_COUNT) 557 data->nprobes++; 558#endif 559 hashval = hash_string(cstring, NULL) % CSTRING_HASHSIZE; 560 for(bp = data->hashtable[hashval]; bp; bp = bp->next){ 561 if(strcmp(cstring, bp->cstring) == 0) 562 return(bp->offset); 563#if defined(DEBUG) && defined(PROBE_COUNT) 564 data->nprobes++; 565#endif 566 } 567 568 cstring_len = strlen(cstring) + 1; 569 len = rnd(cstring_len, 1 << ms->s.align); 570 bp = allocate(sizeof(struct cstring_bucket)); 571 for(p = &(data->cstring_blocks); *p ; p = &(cstring_block->next)){ 572 cstring_block = *p; 573 if(cstring_block->full) 574 continue; 575 if(len > cstring_block->size - cstring_block->used){ 576 cstring_block->full = TRUE; 577 continue; 578 } 579 strcpy(cstring_block->cstrings + cstring_block->used, cstring); 580 memset(cstring_block->cstrings + cstring_block->used + cstring_len, 581 '\0', len - cstring_len); 582 bp->cstring = cstring_block->cstrings + cstring_block->used; 583 cstring_block->used += len; 584 bp->offset = ms->s.size; 585 bp->next = data->hashtable[hashval]; 586 data->hashtable[hashval] = bp; 587 ms->s.size += len; 588#ifdef DEBUG 589 data->noutput_strings++; 590#endif /* DEBUG */ 591 return(bp->offset); 592 } 593 *p = allocate(sizeof(struct cstring_block)); 594 cstring_block = *p; 595 cstring_block->size = (len > host_pagesize ? len : host_pagesize); 596 cstring_block->used = len; 597 cstring_block->full = (len == cstring_block->size ? TRUE : FALSE); 598 cstring_block->next = NULL; 599 cstring_block->cstrings = allocate(cstring_block->size); 600 strcpy(cstring_block->cstrings, cstring); 601 memset(cstring_block->cstrings + cstring_len, '\0', len - cstring_len); 602 bp->cstring = cstring_block->cstrings; 603 bp->offset = ms->s.size; 604 bp->next = data->hashtable[hashval]; 605 data->hashtable[hashval] = bp; 606 ms->s.size += len; 607#ifdef DEBUG 608 data->noutput_strings++; 609#endif /* DEBUG */ 610 return(bp->offset); 611} 612 613/* 614 * cstring_output() copies the cstrings for the data passed to it into the 615 * output file's buffer. The pointer to the merged section passed to it is 616 * used to tell where in the output file this section goes. Then this routine 617 * called cstring_free() to free() up all space used by this data block except 618 * the data block itself. 619 */ 620__private_extern__ 621void 622cstring_output( 623struct cstring_data *data, 624struct merged_section *ms) 625{ 626 unsigned long offset; 627 struct cstring_block **p, *cstring_block; 628 629 /* 630 * Copy the blocks into the output file. 631 */ 632 offset = ms->s.offset; 633 for(p = &(data->cstring_blocks); *p ;){ 634 cstring_block = *p; 635 memcpy(output_addr + offset, 636 cstring_block->cstrings, 637 cstring_block->used); 638 offset += cstring_block->used; 639 p = &(cstring_block->next); 640 } 641#ifndef RLD 642 output_flush(ms->s.offset, offset - ms->s.offset); 643#endif /* !defined(RLD) */ 644 cstring_free(data); 645} 646 647/* 648 * cstring_free() free()'s up all space used by this cstring_data block except 649 * the data block itself. 650 */ 651__private_extern__ 652void 653cstring_free( 654struct cstring_data *data) 655{ 656 unsigned long i; 657 struct cstring_bucket *bp, *next_bp; 658 struct cstring_block *cstring_block, *next_cstring_block; 659 660 /* 661 * Free all data for this block. 662 */ 663 if(data->hashtable != NULL){ 664 for(i = 0; i < CSTRING_HASHSIZE; i++){ 665 for(bp = data->hashtable[i]; bp; ){ 666 next_bp = bp->next; 667 free(bp); 668 bp = next_bp; 669 } 670 } 671 free(data->hashtable); 672 data->hashtable = NULL; 673 } 674 for(cstring_block = data->cstring_blocks; cstring_block ;){ 675 next_cstring_block = cstring_block->next; 676 free(cstring_block->cstrings); 677 free(cstring_block); 678 cstring_block = next_cstring_block; 679 } 680 data->cstring_blocks = NULL; 681} 682 683#ifdef DEBUG 684/* 685 * print_cstring_data() prints a cstring_data. Used for debugging. 686 */ 687__private_extern__ 688void 689print_cstring_data( 690struct cstring_data *data, 691char *indent) 692{ 693 char *s; 694 struct cstring_block **p, *cstring_block; 695/* 696 unsigned long i; 697 struct cstring_bucket *bp; 698*/ 699 700 print("%sC string data at 0x%x\n", indent, (unsigned int)data); 701 if(data == NULL) 702 return; 703 print("%s hashtable 0x%x\n", indent,(unsigned int)(data->hashtable)); 704/* 705 if(data->hashtable != NULL){ 706 for(i = 0; i < CSTRING_HASHSIZE; i++){ 707 print("%s %-3d [0x%x]\n", indent, i, data->hashtable[i]); 708 for(bp = data->hashtable[i]; bp; bp = bp->next){ 709 print("%s\tcstring %s\n", indent, bp->cstring); 710 print("%s\toffset %lu\n", indent, bp->offset); 711 print("%s\tnext 0x%x\n", indent, bp->next); 712 } 713 } 714 } 715*/ 716 print("%s cstring_blocks 0x%x\n", indent, 717 (unsigned int)(data->cstring_blocks)); 718 for(p = &(data->cstring_blocks); *p ; p = &(cstring_block->next)){ 719 cstring_block = *p; 720 print("%s\tsize %lu\n", indent, cstring_block->size); 721 print("%s\tused %lu\n", indent, cstring_block->used); 722 if(cstring_block->full) 723 print("%s\tfull TRUE\n", indent); 724 else 725 print("%s\tfull FALSE\n", indent); 726 print("%s\tnext 0x%x\n", indent, 727 (unsigned int)(cstring_block->next)); 728 print("%s\tcstrings\n", indent); 729 for(s = cstring_block->cstrings; 730 s < cstring_block->cstrings + cstring_block->used; 731 s += strlen(s) + 1){ 732 print("%s\t %s\n", indent, s); 733 } 734 } 735} 736 737/* 738 * cstring_data_stats() prints the cstring_data stats. Used for tuning. 739 */ 740__private_extern__ 741void 742cstring_data_stats( 743struct cstring_data *data, 744struct merged_section *ms) 745{ 746 if(data == NULL) 747 return; 748 print("literal cstring section (%.16s,%.16s) contains:\n", 749 ms->s.segname, ms->s.sectname); 750 print(" %u bytes of merged strings\n", ms->s.size); 751 print(" from %lu files and %lu total bytes from those " 752 "files\n", data->nfiles, data->nbytes); 753 print(" average number of bytes per file %g\n", 754 (double)((double)data->nbytes / (double)(data->nfiles))); 755 print(" %lu merged strings\n", data->noutput_strings); 756 print(" from %lu files and %lu total strings from those " 757 "files\n", data->nfiles, data->ninput_strings); 758 print(" average number of strings per file %g\n", 759 (double)((double)data->ninput_strings / (double)(data->nfiles))); 760 if(data->nprobes != 0){ 761 print(" number of hash probes %lu\n", data->nprobes); 762 print(" average number of hash probes %g\n", 763 (double)((double)(data->nprobes) / (double)(data->ninput_strings))); 764 } 765} 766#endif /* DEBUG */ 767