1 /** 2 * @file jitsymbol.c 3 * Handle symbols found in jitted code dump 4 * 5 * @remark Copyright 2007 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Jens Wilke 9 * @Modifications Maynard Johnson 10 * @Modifications Philippe Elie 11 * @Modifications Daniel Hansel 12 * 13 * Copyright IBM Corporation 2007 14 * 15 */ 16 17 #include "opjitconv.h" 18 #include "opd_printf.h" 19 #include "op_libiberty.h" 20 #include "op_types.h" 21 22 #include <stddef.h> 23 #include <stdlib.h> 24 #include <stdint.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <unistd.h> 28 #include <limits.h> 29 30 typedef int (*compare_symbol)(void const *, void const *); 31 32 33 /* count the entries in the jitentry_list */ 34 static u32 count_entries(void) 35 { 36 struct jitentry const * entry; 37 u32 cnt = 0; 38 for (entry = jitentry_list; entry; entry = entry->next) 39 cnt++; 40 return cnt; 41 } 42 43 44 static void fill_entry_array(struct jitentry * entries[]) 45 { 46 int i = 0; 47 struct jitentry * entry; 48 for (entry = jitentry_list; entry; entry = entry->next) 49 entries[i++] = entry; 50 } 51 52 53 /* create an array pointing to the jitentry structures which is sorted 54 * according to the comparator rule given by parameter compar 55 */ 56 static struct jitentry ** create_sorted_array(compare_symbol compare) 57 { 58 struct jitentry ** array = 59 xmalloc(sizeof(struct jitentry *) * entry_count); 60 fill_entry_array(array); 61 qsort(array, entry_count, sizeof(struct jitentry *), compare); 62 return array; 63 } 64 65 66 /* comparator method for qsort which sorts jitentries by symbol_name */ 67 static int cmp_symbolname(void const * a, void const * b) 68 { 69 struct jitentry * a0 = *(struct jitentry **) a; 70 struct jitentry * b0 = *(struct jitentry **) b; 71 return strcmp(a0->symbol_name, b0->symbol_name); 72 } 73 74 75 /* comparator method for qsort which sorts jitentries by address */ 76 static int cmp_address(void const * a, void const * b) 77 { 78 struct jitentry * a0 = *(struct jitentry **) a; 79 struct jitentry * b0 = *(struct jitentry **) b; 80 if (a0->vma < b0->vma) 81 return -1; 82 if (a0->vma == b0->vma) 83 return 0; 84 return 1; 85 } 86 87 88 /* resort address_ascending array */ 89 static void resort_address(void) 90 { 91 u32 i; 92 93 qsort(entries_address_ascending, entry_count, 94 sizeof(struct jitentry *), cmp_address); 95 96 // lower entry_count if entries are invalidated 97 for (i = 0; i < entry_count; ++i) { 98 if (entries_address_ascending[i]->vma) 99 break; 100 } 101 102 if (i) { 103 entry_count -= i; 104 memmove(&entries_address_ascending[0], 105 &entries_address_ascending[i], 106 sizeof(struct jitentry *) * entry_count); 107 } 108 } 109 110 111 /* Copy address_ascending array to entries_symbols_ascending and resort it. */ 112 static void resort_symbol(void) 113 { 114 memcpy(entries_symbols_ascending, entries_address_ascending, 115 sizeof(struct jitentry *) * entry_count); 116 qsort(entries_symbols_ascending, entry_count, 117 sizeof(struct jitentry *), cmp_symbolname); 118 } 119 120 /* allocate, populate and sort the jitentry arrays */ 121 void create_arrays(void) 122 { 123 max_entry_count = entry_count = count_entries(); 124 entries_symbols_ascending = create_sorted_array(cmp_symbolname); 125 entries_address_ascending = create_sorted_array(cmp_address); 126 } 127 128 129 /* add a new create jitentry to the array. mallocs new arrays if space is 130 * needed */ 131 static void insert_entry(struct jitentry * entry) 132 { 133 if (entry_count == max_entry_count) { 134 if (max_entry_count < UINT32_MAX - 18) 135 max_entry_count += 18; 136 else if (max_entry_count < UINT32_MAX) 137 max_entry_count += 1; 138 else { 139 fprintf(stderr, "Amount of JIT dump file entries is too large.\n"); 140 exit(EXIT_FAILURE); 141 } 142 entries_symbols_ascending = (struct jitentry **) 143 xrealloc(entries_symbols_ascending, 144 sizeof(struct jitentry *) * max_entry_count); 145 entries_address_ascending = (struct jitentry **) 146 xrealloc(entries_address_ascending, 147 sizeof(struct jitentry *) * max_entry_count); 148 } 149 entries_address_ascending[entry_count++] = entry; 150 } 151 152 153 /* add a suffix to the name to differenciate it */ 154 static char * replacement_name(char * s, int i) 155 { 156 int cnt = 1; 157 int j = i; 158 char * res; 159 160 while ((j = j/10)) 161 cnt++; 162 cnt += 2 + strlen(s); 163 res = xmalloc(cnt); 164 snprintf(res, cnt, "%s~%i", s, i); 165 return res; 166 } 167 168 169 /* 170 * Mark the entry so it is not included in the ELF file. We do this by 171 * writing a 0 address as magic vma and sorting 172 * it out later 173 */ 174 static void invalidate_entry(struct jitentry * e) 175 { 176 verbprintf(debug, "invalidate_entry: addr=%llx, name=%s\n", 177 e->vma, e->symbol_name); 178 e->vma = 0; 179 } 180 181 182 /* 183 * Invalidate all symbols that are not alive at sampling start time. 184 */ 185 static void invalidate_earlybirds(unsigned long long start_time) 186 { 187 u32 i; 188 int flag; 189 struct jitentry * a; 190 191 flag = 0; 192 for (i = 0; i < entry_count; i++) { 193 a = entries_address_ascending[i]; 194 if (a->life_end < start_time) { 195 invalidate_entry(a); 196 flag = 1; 197 } 198 } 199 if (flag) { 200 resort_address(); 201 resort_symbol(); 202 } 203 } 204 205 206 /* select the symbol with the longest life time in the index range */ 207 static int select_one(int start_idx, int end_idx) 208 { 209 int i; 210 int candidate = OP_JIT_CONV_FAIL; 211 unsigned long long lifetime = 0; 212 unsigned long long x; 213 struct jitentry const * e; 214 215 for (i = start_idx; i <= end_idx; i++) { 216 e = entries_address_ascending[i]; 217 x = e->life_end - e->life_start; 218 if (candidate == -1 || x > lifetime) { 219 candidate = i; 220 lifetime = x; 221 } 222 } 223 return candidate; 224 } 225 226 227 /* 228 * We decided to keep one entry in favor of the other. Instead of dropping 229 * the overlapping entry we split or truncate it to not overlap any more. 230 * 231 * Looking on the address regions, we may have the following situation: 232 * 233 * split: |------------| 234 * keep: |---| 235 * 236 * The split entry may be splitted in a left part and a right part. E.g.: 237 * 238 * split0/1: |--| |---| 239 * keep: |---| 240 * 241 * However, both parts may or may not exist. 242 */ 243 static void split_entry(struct jitentry * split, struct jitentry const * keep) 244 { 245 unsigned long long start_addr_keep = keep->vma; 246 unsigned long long end_addr_keep = keep->vma + keep->code_size; 247 unsigned long long end_addr_split = split->vma + split->code_size; 248 unsigned long long start_addr_split = split->vma; 249 250 // do we need a right part? 251 if (end_addr_split > end_addr_keep) { 252 struct jitentry * new_entry = 253 xcalloc(1, sizeof(struct jitentry)); 254 char * s = NULL; 255 256 /* Check for max. length to avoid possible integer overflow. */ 257 if (strlen(split->symbol_name) > SIZE_MAX - 3) { 258 fprintf(stderr, "Length of symbol name is too large.\n"); 259 exit(EXIT_FAILURE); 260 } else { 261 s = xmalloc(strlen(split->symbol_name) + 3); 262 strcpy(s, split->symbol_name); 263 strcat(s, "#1"); 264 } 265 266 new_entry->vma = end_addr_keep; 267 new_entry->code_size = end_addr_split - end_addr_keep; 268 new_entry->symbol_name = s; 269 new_entry->sym_name_malloced = 1; 270 new_entry->life_start = split->life_start; 271 new_entry->life_end = split->life_end; 272 // the right part does not have an associated code, because we 273 // don't know whether the split part begins at an opcode 274 new_entry->code = NULL; 275 verbprintf(debug, "split right (new) name=%s, start=%llx," 276 " end=%llx\n", new_entry->symbol_name, 277 new_entry->vma, 278 new_entry->vma + new_entry->code_size); 279 insert_entry(new_entry); 280 } 281 // do we need a left part? 282 if (start_addr_split < start_addr_keep) { 283 char * s = NULL; 284 285 /* Check for max. length to avoid possible integer overflow. */ 286 if (strlen(split->symbol_name) > SIZE_MAX - 3) { 287 fprintf(stderr, "Length of symbol name is too large.\n"); 288 exit(EXIT_FAILURE); 289 } else { 290 s = xmalloc(strlen(split->symbol_name) + 3); 291 strcpy(s, split->symbol_name); 292 strcat(s, "#0"); 293 } 294 295 split->code_size = start_addr_keep - start_addr_split; 296 if (split->sym_name_malloced) 297 free(split->symbol_name); 298 split->symbol_name = s; 299 split->sym_name_malloced = 1; 300 verbprintf(debug, "split left name=%s, start=%llx, end=%llx\n", 301 split->symbol_name, split->vma, 302 split->vma + split->code_size); 303 } else { 304 invalidate_entry(split); 305 } 306 } 307 308 309 /* 310 * Scans through the index range and splits/truncates entries that overlap 311 * with the one indexed by keep_idx. Returns the total lifetime of the symbols 312 * found to overlap. 313 * Returns ULONG_MAX on error. 314 */ 315 static unsigned long long eliminate_overlaps(int start_idx, int end_idx, 316 int keep_idx) 317 { 318 unsigned long long retval; 319 struct jitentry const * keep = entries_address_ascending[keep_idx]; 320 struct jitentry * e; 321 unsigned long long start_addr_keep = keep->vma; 322 unsigned long long end_addr_keep = keep->vma + keep->code_size; 323 unsigned long long start_addr_entry, end_addr_entry; 324 int i; 325 unsigned long long min_start = keep->life_start; 326 unsigned long long max_end = keep->life_end; 327 328 for (i = start_idx; i <= end_idx; i++) { 329 if (i == keep_idx) 330 continue; 331 e = entries_address_ascending[i]; 332 start_addr_entry = e->vma; 333 end_addr_entry = e->vma + e->code_size; 334 if (debug) { 335 if (!(start_addr_entry <= end_addr_entry)) { 336 verbprintf(debug, "assert failed:" 337 " start_addr_entry <=" 338 " end_addr_entry\n"); 339 retval = ULONG_MAX; 340 goto out; 341 } 342 if (!(start_addr_keep <= end_addr_keep)) { 343 verbprintf(debug, "assert failed: " 344 "start_addr_keep <=" 345 " end_addr_keep\n"); 346 retval = ULONG_MAX; 347 goto out; 348 } 349 } 350 if (start_addr_entry < end_addr_keep && 351 end_addr_entry > start_addr_keep) { 352 if (e->life_start < min_start) 353 min_start = e->life_start; 354 if (e->life_end > max_end) 355 max_end = e->life_end; 356 split_entry(e, keep); 357 } 358 } 359 retval = max_end - min_start; 360 out: 361 return retval; 362 } 363 364 365 /* 366 * Within the index range (into the array entries_address_ascending), find the 367 * symbol with the maximal lifetime and split/truncate all symbols that overlap 368 * with it (i.e. that there won't be any overlaps anymore). 369 */ 370 static int handle_overlap_region(int start_idx, int end_idx) 371 { 372 int rc = OP_JIT_CONV_OK; 373 int idx; 374 struct jitentry * e; 375 int cnt; 376 char * name; 377 int i, j; 378 unsigned long long totaltime; 379 380 if (debug) { 381 for (i = start_idx; i <= end_idx; i++) { 382 e = entries_address_ascending[i]; 383 verbprintf(debug, "overlap idx=%i, name=%s, " 384 "start=%llx, end=%llx, life_start=%lli, " 385 "life_end=%lli, lifetime=%lli\n", 386 i, e->symbol_name, e->vma, 387 e->vma + e->code_size, e->life_start, 388 e->life_end, e->life_end - e->life_start); 389 } 390 } 391 idx = select_one(start_idx, end_idx); 392 totaltime = eliminate_overlaps(start_idx, end_idx, idx); 393 if (totaltime == ULONG_MAX) { 394 rc = OP_JIT_CONV_FAIL; 395 goto out; 396 } 397 e = entries_address_ascending[idx]; 398 399 cnt = 1; 400 j = (e->life_end - e->life_start) * 100 / totaltime; 401 while ((j = j/10)) 402 cnt++; 403 404 // Mark symbol name with a %% to indicate the overlap. 405 cnt += strlen(e->symbol_name) + 2 + 1; 406 name = xmalloc(cnt); 407 snprintf(name, cnt, "%s%%%llu", e->symbol_name, 408 (e->life_end - e->life_start) * 100 / totaltime); 409 if (e->sym_name_malloced) 410 free(e->symbol_name); 411 e->symbol_name = name; 412 e->sym_name_malloced = 1; 413 verbprintf(debug, "selected idx=%i, name=%s\n", idx, e->symbol_name); 414 out: 415 return rc; 416 } 417 418 419 /* 420 * one scan through the symbols to find overlaps. 421 * return 1 if an overlap is found. this is repeated until no more overlap 422 * is there. 423 * Process: There may be more than two overlapping symbols with each other. 424 * The index range of symbols found to overlap are passed to 425 * handle_overlap_region. 426 */ 427 static int scan_overlaps(void) 428 { 429 int i, j; 430 unsigned long long end_addr, end_addr2; 431 struct jitentry const * a; 432 int flag = 0; 433 // entry_count can be incremented by split_entry() during the loop, 434 // save the inital value as loop count 435 int loop_count = entry_count; 436 437 verbprintf(debug,"count=%i, scan overlaps...\n", entry_count); 438 i = 0; 439 end_addr = 0; 440 for (j = 1; j < loop_count; j++) { 441 /** 442 * Take a symbol [i] and look for the next symbol(s) [j] that are overlapping 443 * symbol [i]. If a symbol [j] is found that is not overlapping symbol [i] the 444 * symbols [i]..[j-1] are handled to be not overlapping anymore. 445 * See descriptions of handle_overlap_region() and eliminate_overlaps() for 446 * further details of this handling. 447 * E.g. possible cases to be handled could be: 448 * 449 * sym1 |-----------| 450 * sym2 |---| 451 * 452 * sym1 |--------| 453 * sym2 |--------| 454 * 455 * sym1 |--------| 456 * sym2 |-------| 457 * sym3 |---------| 458 * 459 * But in the following case 460 * 461 * sym1 |--------| 462 * sym2 |-------------| 463 * sym3 |----------| 464 * 465 * sym3 would not overlap with sym1. Therefore handle_overlap_regio() would 466 * only be called for sym1 up to sym2. 467 */ 468 a = entries_address_ascending[j - 1]; 469 end_addr2 = a->vma + a->code_size; 470 if (end_addr2 > end_addr) 471 end_addr = end_addr2; 472 a = entries_address_ascending[j]; 473 if (end_addr <= a->vma) { 474 if (i != j - 1) { 475 if (handle_overlap_region(i, j - 1) == 476 OP_JIT_CONV_FAIL) { 477 flag = OP_JIT_CONV_FAIL; 478 goto out; 479 } 480 flag = 1; 481 } 482 i = j; 483 } 484 } 485 if (i != j - 1) { 486 if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL) 487 flag = OP_JIT_CONV_FAIL; 488 else 489 flag = 1; 490 } 491 out: 492 return flag; 493 } 494 495 496 /* search for symbols that have overlapping address ranges and decide for 497 * one */ 498 int resolve_overlaps(unsigned long long start_time) 499 { 500 int rc = OP_JIT_CONV_OK; 501 int cnt = 0; 502 503 invalidate_earlybirds(start_time); 504 while ((rc = scan_overlaps()) && rc != OP_JIT_CONV_FAIL) { 505 resort_address(); 506 if (cnt == 0) { 507 verbprintf(debug, "WARNING: overlaps detected. " 508 "Removing overlapping JIT methods\n"); 509 } 510 cnt++; 511 } 512 if (cnt > 0 && rc != OP_JIT_CONV_FAIL) 513 resort_symbol(); 514 return rc; 515 } 516 517 518 /* 519 * scan through the sorted array and replace identical symbol names by unique 520 * ones by adding a counter value. 521 */ 522 void disambiguate_symbol_names(void) 523 { 524 u32 j; 525 int cnt, rep_cnt; 526 struct jitentry * a; 527 struct jitentry * b; 528 529 rep_cnt = 0; 530 for (j = 1; j < entry_count; j++) { 531 a = entries_symbols_ascending[j - 1]; 532 cnt = 1; 533 do { 534 b = entries_symbols_ascending[j]; 535 if (strcmp(a->symbol_name, b->symbol_name) == 0) { 536 if (b->sym_name_malloced) 537 free(b->symbol_name); 538 b->symbol_name = 539 replacement_name(a->symbol_name, cnt); 540 b->sym_name_malloced = 1; 541 j++; 542 cnt++; 543 rep_cnt++; 544 } else { 545 break; 546 } 547 } while (j < entry_count); 548 } 549 /* recurse to avoid that the added suffix also creates a collision */ 550 if (rep_cnt) { 551 qsort(entries_symbols_ascending, entry_count, 552 sizeof(struct jitentry *), cmp_symbolname); 553 disambiguate_symbol_names(); 554 } 555 } 556