00001
00017 #include "opjitconv.h"
00018 #include "opd_printf.h"
00019 #include "op_libiberty.h"
00020 #include "op_types.h"
00021
00022 #include <stddef.h>
00023 #include <stdlib.h>
00024 #include <stdint.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <limits.h>
00029
00030 typedef int (*compare_symbol)(void const *, void const *);
00031
00032
00033
00034 static u32 count_entries(void)
00035 {
00036 struct jitentry const * entry;
00037 u32 cnt = 0;
00038 for (entry = jitentry_list; entry; entry = entry->next)
00039 cnt++;
00040 return cnt;
00041 }
00042
00043
00044 static void fill_entry_array(struct jitentry * entries[])
00045 {
00046 int i = 0;
00047 struct jitentry * entry;
00048 for (entry = jitentry_list; entry; entry = entry->next)
00049 entries[i++] = entry;
00050 }
00051
00052
00053
00054
00055
00056 static struct jitentry ** create_sorted_array(compare_symbol compare)
00057 {
00058 struct jitentry ** array =
00059 xmalloc(sizeof(struct jitentry *) * entry_count);
00060 fill_entry_array(array);
00061 qsort(array, entry_count, sizeof(struct jitentry *), compare);
00062 return array;
00063 }
00064
00065
00066
00067 static int cmp_symbolname(void const * a, void const * b)
00068 {
00069 struct jitentry * a0 = *(struct jitentry **) a;
00070 struct jitentry * b0 = *(struct jitentry **) b;
00071 return strcmp(a0->symbol_name, b0->symbol_name);
00072 }
00073
00074
00075
00076 static int cmp_address(void const * a, void const * b)
00077 {
00078 struct jitentry * a0 = *(struct jitentry **) a;
00079 struct jitentry * b0 = *(struct jitentry **) b;
00080 if (a0->vma < b0->vma)
00081 return -1;
00082 if (a0->vma == b0->vma)
00083 return 0;
00084 return 1;
00085 }
00086
00087
00088
00089 static void resort_address(void)
00090 {
00091 u32 i;
00092
00093 qsort(entries_address_ascending, entry_count,
00094 sizeof(struct jitentry *), cmp_address);
00095
00096
00097 for (i = 0; i < entry_count; ++i) {
00098 if (entries_address_ascending[i]->vma)
00099 break;
00100 }
00101
00102 if (i) {
00103 entry_count -= i;
00104 memmove(&entries_address_ascending[0],
00105 &entries_address_ascending[i],
00106 sizeof(struct jitentry *) * entry_count);
00107 }
00108 }
00109
00110
00111
00112 static void resort_symbol(void)
00113 {
00114 memcpy(entries_symbols_ascending, entries_address_ascending,
00115 sizeof(struct jitentry *) * entry_count);
00116 qsort(entries_symbols_ascending, entry_count,
00117 sizeof(struct jitentry *), cmp_symbolname);
00118 }
00119
00120
00121 void create_arrays(void)
00122 {
00123 max_entry_count = entry_count = count_entries();
00124 entries_symbols_ascending = create_sorted_array(cmp_symbolname);
00125 entries_address_ascending = create_sorted_array(cmp_address);
00126 }
00127
00128
00129
00130
00131 static void insert_entry(struct jitentry * entry)
00132 {
00133 if (entry_count == max_entry_count) {
00134 if (max_entry_count < UINT32_MAX - 18)
00135 max_entry_count += 18;
00136 else if (max_entry_count < UINT32_MAX)
00137 max_entry_count += 1;
00138 else {
00139 fprintf(stderr, "Amount of JIT dump file entries is too large.\n");
00140 exit(EXIT_FAILURE);
00141 }
00142 entries_symbols_ascending = (struct jitentry **)
00143 xrealloc(entries_symbols_ascending,
00144 sizeof(struct jitentry *) * max_entry_count);
00145 entries_address_ascending = (struct jitentry **)
00146 xrealloc(entries_address_ascending,
00147 sizeof(struct jitentry *) * max_entry_count);
00148 }
00149 entries_address_ascending[entry_count++] = entry;
00150 }
00151
00152
00153
00154 static char * replacement_name(char * s, int i)
00155 {
00156 int cnt = 1;
00157 int j = i;
00158 char * res;
00159
00160 while ((j = j/10))
00161 cnt++;
00162 cnt += 2 + strlen(s);
00163 res = xmalloc(cnt);
00164 snprintf(res, cnt, "%s~%i", s, i);
00165 return res;
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 static void invalidate_entry(struct jitentry * e)
00175 {
00176 verbprintf(debug, "invalidate_entry: addr=%llx, name=%s\n",
00177 e->vma, e->symbol_name);
00178 e->vma = 0;
00179 }
00180
00181
00182
00183
00184
00185 static void invalidate_earlybirds(unsigned long long start_time)
00186 {
00187 u32 i;
00188 int flag;
00189 struct jitentry * a;
00190
00191 flag = 0;
00192 for (i = 0; i < entry_count; i++) {
00193 a = entries_address_ascending[i];
00194 if (a->life_end < start_time) {
00195 invalidate_entry(a);
00196 flag = 1;
00197 }
00198 }
00199 if (flag) {
00200 resort_address();
00201 resort_symbol();
00202 }
00203 }
00204
00205
00206
00207 static int select_one(int start_idx, int end_idx)
00208 {
00209 int i;
00210 int candidate = OP_JIT_CONV_FAIL;
00211 unsigned long long lifetime = 0;
00212 unsigned long long x;
00213 struct jitentry const * e;
00214
00215 for (i = start_idx; i <= end_idx; i++) {
00216 e = entries_address_ascending[i];
00217 x = e->life_end - e->life_start;
00218 if (candidate == -1 || x > lifetime) {
00219 candidate = i;
00220 lifetime = x;
00221 }
00222 }
00223 return candidate;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 static void split_entry(struct jitentry * split, struct jitentry const * keep)
00244 {
00245 unsigned long long start_addr_keep = keep->vma;
00246 unsigned long long end_addr_keep = keep->vma + keep->code_size;
00247 unsigned long long end_addr_split = split->vma + split->code_size;
00248 unsigned long long start_addr_split = split->vma;
00249
00250
00251 if (end_addr_split > end_addr_keep) {
00252 struct jitentry * new_entry =
00253 xcalloc(1, sizeof(struct jitentry));
00254 char * s = NULL;
00255
00256
00257 if (strlen(split->symbol_name) > SIZE_MAX - 3) {
00258 fprintf(stderr, "Length of symbol name is too large.\n");
00259 exit(EXIT_FAILURE);
00260 } else {
00261 s = xmalloc(strlen(split->symbol_name) + 3);
00262 strcpy(s, split->symbol_name);
00263 strcat(s, "#1");
00264 }
00265
00266 new_entry->vma = end_addr_keep;
00267 new_entry->code_size = end_addr_split - end_addr_keep;
00268 new_entry->symbol_name = s;
00269 new_entry->sym_name_malloced = 1;
00270 new_entry->life_start = split->life_start;
00271 new_entry->life_end = split->life_end;
00272
00273
00274 new_entry->code = NULL;
00275 verbprintf(debug, "split right (new) name=%s, start=%llx,"
00276 " end=%llx\n", new_entry->symbol_name,
00277 new_entry->vma,
00278 new_entry->vma + new_entry->code_size);
00279 insert_entry(new_entry);
00280 }
00281
00282 if (start_addr_split < start_addr_keep) {
00283 char * s = NULL;
00284
00285
00286 if (strlen(split->symbol_name) > SIZE_MAX - 3) {
00287 fprintf(stderr, "Length of symbol name is too large.\n");
00288 exit(EXIT_FAILURE);
00289 } else {
00290 s = xmalloc(strlen(split->symbol_name) + 3);
00291 strcpy(s, split->symbol_name);
00292 strcat(s, "#0");
00293 }
00294
00295 split->code_size = start_addr_keep - start_addr_split;
00296 if (split->sym_name_malloced)
00297 free(split->symbol_name);
00298 split->symbol_name = s;
00299 split->sym_name_malloced = 1;
00300 verbprintf(debug, "split left name=%s, start=%llx, end=%llx\n",
00301 split->symbol_name, split->vma,
00302 split->vma + split->code_size);
00303 } else {
00304 invalidate_entry(split);
00305 }
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315 static unsigned long long eliminate_overlaps(int start_idx, int end_idx,
00316 int keep_idx)
00317 {
00318 unsigned long long retval;
00319 struct jitentry const * keep = entries_address_ascending[keep_idx];
00320 struct jitentry * e;
00321 unsigned long long start_addr_keep = keep->vma;
00322 unsigned long long end_addr_keep = keep->vma + keep->code_size;
00323 unsigned long long start_addr_entry, end_addr_entry;
00324 int i;
00325 unsigned long long min_start = keep->life_start;
00326 unsigned long long max_end = keep->life_end;
00327
00328 for (i = start_idx; i <= end_idx; i++) {
00329 if (i == keep_idx)
00330 continue;
00331 e = entries_address_ascending[i];
00332 start_addr_entry = e->vma;
00333 end_addr_entry = e->vma + e->code_size;
00334 if (debug) {
00335 if (!(start_addr_entry <= end_addr_entry)) {
00336 verbprintf(debug, "assert failed:"
00337 " start_addr_entry <="
00338 " end_addr_entry\n");
00339 retval = ULONG_MAX;
00340 goto out;
00341 }
00342 if (!(start_addr_keep <= end_addr_keep)) {
00343 verbprintf(debug, "assert failed: "
00344 "start_addr_keep <="
00345 " end_addr_keep\n");
00346 retval = ULONG_MAX;
00347 goto out;
00348 }
00349 }
00350 if (start_addr_entry < end_addr_keep &&
00351 end_addr_entry > start_addr_keep) {
00352 if (e->life_start < min_start)
00353 min_start = e->life_start;
00354 if (e->life_end > max_end)
00355 max_end = e->life_end;
00356 split_entry(e, keep);
00357 }
00358 }
00359 retval = max_end - min_start;
00360 out:
00361 return retval;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370 static int handle_overlap_region(int start_idx, int end_idx)
00371 {
00372 int rc = OP_JIT_CONV_OK;
00373 int idx;
00374 struct jitentry * e;
00375 int cnt;
00376 char * name;
00377 int i, j;
00378 unsigned long long totaltime;
00379
00380 if (debug) {
00381 for (i = start_idx; i <= end_idx; i++) {
00382 e = entries_address_ascending[i];
00383 verbprintf(debug, "overlap idx=%i, name=%s, "
00384 "start=%llx, end=%llx, life_start=%lli, "
00385 "life_end=%lli, lifetime=%lli\n",
00386 i, e->symbol_name, e->vma,
00387 e->vma + e->code_size, e->life_start,
00388 e->life_end, e->life_end - e->life_start);
00389 }
00390 }
00391 idx = select_one(start_idx, end_idx);
00392 totaltime = eliminate_overlaps(start_idx, end_idx, idx);
00393 if (totaltime == ULONG_MAX) {
00394 rc = OP_JIT_CONV_FAIL;
00395 goto out;
00396 }
00397 e = entries_address_ascending[idx];
00398
00399 cnt = 1;
00400 j = (e->life_end - e->life_start) * 100 / totaltime;
00401 while ((j = j/10))
00402 cnt++;
00403
00404
00405 cnt += strlen(e->symbol_name) + 2 + 1;
00406 name = xmalloc(cnt);
00407 snprintf(name, cnt, "%s%%%llu", e->symbol_name,
00408 (e->life_end - e->life_start) * 100 / totaltime);
00409 if (e->sym_name_malloced)
00410 free(e->symbol_name);
00411 e->symbol_name = name;
00412 e->sym_name_malloced = 1;
00413 verbprintf(debug, "selected idx=%i, name=%s\n", idx, e->symbol_name);
00414 out:
00415 return rc;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 static int scan_overlaps(void)
00428 {
00429 int i, j;
00430 unsigned long long end_addr, end_addr2;
00431 struct jitentry const * a;
00432 int flag = 0;
00433
00434
00435 int loop_count = entry_count;
00436
00437 verbprintf(debug,"count=%i, scan overlaps...\n", entry_count);
00438 i = 0;
00439 end_addr = 0;
00440 for (j = 1; j < loop_count; j++) {
00468 a = entries_address_ascending[j - 1];
00469 end_addr2 = a->vma + a->code_size;
00470 if (end_addr2 > end_addr)
00471 end_addr = end_addr2;
00472 a = entries_address_ascending[j];
00473 if (end_addr <= a->vma) {
00474 if (i != j - 1) {
00475 if (handle_overlap_region(i, j - 1) ==
00476 OP_JIT_CONV_FAIL) {
00477 flag = OP_JIT_CONV_FAIL;
00478 goto out;
00479 }
00480 flag = 1;
00481 }
00482 i = j;
00483 }
00484 }
00485 if (i != j - 1) {
00486 if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL)
00487 flag = OP_JIT_CONV_FAIL;
00488 else
00489 flag = 1;
00490 }
00491 out:
00492 return flag;
00493 }
00494
00495
00496
00497
00498 int resolve_overlaps(unsigned long long start_time)
00499 {
00500 int rc = OP_JIT_CONV_OK;
00501 int cnt = 0;
00502
00503 invalidate_earlybirds(start_time);
00504 while ((rc = scan_overlaps()) && rc != OP_JIT_CONV_FAIL) {
00505 resort_address();
00506 if (cnt == 0) {
00507 verbprintf(debug, "WARNING: overlaps detected. "
00508 "Removing overlapping JIT methods\n");
00509 }
00510 cnt++;
00511 }
00512 if (cnt > 0 && rc != OP_JIT_CONV_FAIL)
00513 resort_symbol();
00514 return rc;
00515 }
00516
00517
00518
00519
00520
00521
00522 void disambiguate_symbol_names(void)
00523 {
00524 u32 j;
00525 int cnt, rep_cnt;
00526 struct jitentry * a;
00527 struct jitentry * b;
00528
00529 rep_cnt = 0;
00530 for (j = 1; j < entry_count; j++) {
00531 a = entries_symbols_ascending[j - 1];
00532 cnt = 1;
00533 do {
00534 b = entries_symbols_ascending[j];
00535 if (strcmp(a->symbol_name, b->symbol_name) == 0) {
00536 if (b->sym_name_malloced)
00537 free(b->symbol_name);
00538 b->symbol_name =
00539 replacement_name(a->symbol_name, cnt);
00540 b->sym_name_malloced = 1;
00541 j++;
00542 cnt++;
00543 rep_cnt++;
00544 } else {
00545 break;
00546 }
00547 } while (j < entry_count);
00548 }
00549
00550 if (rep_cnt) {
00551 qsort(entries_symbols_ascending, entry_count,
00552 sizeof(struct jitentry *), cmp_symbolname);
00553 disambiguate_symbol_names();
00554 }
00555 }