From: Philippe E. <ph...@us...> - 2007-11-17 15:26:33
|
Update of /cvsroot/oprofile/oprofile/opjitconv In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv2589/opjitconv Modified Files: Tag: JIT_SUPPORT Makefile.am opjitconv.c Added Files: Tag: JIT_SUPPORT create_bfd.c jitsymbol.c opjitconv.h parse_dump.c Log Message: split opjitconv.c in multiple files, no other change than cut and copy --- NEW FILE: create_bfd.c --- /** * @file create_bfd.c * Routine to handle elf file creation * * @remark Copyright 2007 OProfile authors * @remark Read the file COPYING * * @author Jens Wilke * @Modifications Maynard Johnson * @Modifications Philippe Elie * * Copyright IBM Corporation 2007 * */ #include "opjitconv.h" #include "opd_printf.h" #include <bfd.h> #include <stdint.h> #include <stdio.h> /* Create the symbols and fill the syms array for all functions * from start_idx to end_idx pointing into entries_address_ascending array */ static int fill_symtab() { int rc = OP_JIT_CONV_OK; int i, r; struct jitentry * e; asymbol * s; asection * section = NULL; syms = (asymbol **)op_jit_malloc(sizeof(asymbol *) * (entry_count+1)); syms[entry_count] = NULL; for (i = 0; i < entry_count; i++) { e = entries_address_ascending[i]; if (e->section) { section = e->section; } s = bfd_make_empty_symbol(cur_bfd); if (s == NULL) { bfd_perror("bfd_make_empty_symbol"); rc = OP_JIT_CONV_FAIL; goto out; } s->name = e->symbol_name; s->section = section; s->flags = BSF_GLOBAL | BSF_FUNCTION; s->value = e->code_addr - section->vma; verbprintf(debug,"add sym: name=%s, value=%llx\n", s->name, s->value); syms[i] = s; } r = bfd_set_symtab(cur_bfd, syms, entry_count); if (r == FALSE) { bfd_perror("bfd_set_symtab"); rc = OP_JIT_CONV_FAIL; goto out; } out: return rc; } /* create the .text section. end_idx: index last jitentry (inclusive!) */ static int create_section(int start_idx, int end_idx) { int rc = OP_JIT_CONV_OK; asection * section; char * section_name; int r; int idx = start_idx; unsigned long long vma_start = entries_address_ascending[start_idx]->code_addr; struct jitentry * ee = entries_address_ascending[end_idx]; unsigned long long vma_end = ee->code_addr + ee->code_size; int size = vma_end - vma_start; section_name = bfd_get_unique_section_name(cur_bfd, ".text", &idx); verbprintf(debug, "section idx=%i, name=%s, vma_start=%llx, size=%i\n", idx, section_name, vma_start, size); section = bfd_make_section(cur_bfd, section_name); if (section == NULL) { bfd_perror("bfd_make_section"); rc = OP_JIT_CONV_FAIL; goto out; } entries_address_ascending[start_idx]->section = section; r = bfd_set_section_size(cur_bfd, section, size); if (r == FALSE) { bfd_perror("bfd_set_section_size"); rc = OP_JIT_CONV_FAIL; goto out; } r = bfd_set_section_vma(cur_bfd, section, vma_start); if (r == FALSE) { bfd_perror("bfd_set_section_vma"); rc = OP_JIT_CONV_FAIL; goto out; } r = bfd_set_section_flags(cur_bfd, section, SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_HAS_CONTENTS); if (r == FALSE) { bfd_perror("bfd_set_section_flags"); rc = OP_JIT_CONV_FAIL; goto out; } out: return rc; } /* * Copy all code of the functions that are within start_idx and end_idx to * the section. */ static int fill_section_content(asection * section, int start_idx, int end_idx) { int rc = OP_JIT_CONV_OK; unsigned long long vma_start = entries_address_ascending[start_idx]-> code_addr; struct jitentry * e; bfd_boolean r; int i; for (i = start_idx; i <= end_idx; i++) { e = entries_address_ascending[i]; verbprintf(debug, "section = %s, i = %i, code = %llx," " code_addr = %llx, offset = %llx," "size = %i, name = %s\n", section->name, i, (unsigned long long) (uintptr_t) e->code, e->code_addr, e->code_addr - vma_start, e->code_size, e->symbol_name); /* the right part that is created by split_entry may * hav no code. */ if (e->code != NULL) { r = bfd_set_section_contents( cur_bfd, section, e->code, (file_ptr) (e->code_addr - vma_start), (bfd_size_type) e->code_size); if (r == FALSE) { bfd_perror("bfd_set_section_contents"); rc = OP_JIT_CONV_FAIL; break; } } } return rc; } /* Walk over the symbols sorted by address and create ELF sections. Whenever we * have a gap greater or equal to 4096 make a new section. */ int partition_sections() { int rc = OP_JIT_CONV_OK; int i, j; struct jitentry * pred; struct jitentry * entry; unsigned long long end_addr; // i: start index of the section i = 0; pred = entries_address_ascending[i]; for (j = i + 1; j < entry_count; j++) { entry = entries_address_ascending[j]; end_addr = pred->code_addr + pred->code_size; // calculate gap between code, if it is more than one page // create an additional section if ( (entry->code_addr - end_addr) >= 4096) { rc = create_section(i, j - 1); if (rc == OP_JIT_CONV_FAIL) goto out; i = j; } pred = entry; } // this holds always if we have at least one jitentry if (i < entry_count) { rc = create_section(i, entry_count - 1); } out: return rc; } /* Fill the code content into the sections created by split_sections */ int fill_sections() { int rc = OP_JIT_CONV_OK; int i, j; asection * section; rc = fill_symtab(); if (rc == OP_JIT_CONV_FAIL) goto out; i = 0; for (j = i + 1; j < entry_count; j++) { if (entries_address_ascending[j]->section != NULL) { section = entries_address_ascending[i]->section; rc = fill_section_content(section, i, j - 1); if (rc == OP_JIT_CONV_FAIL) goto out; i = j; } } if (i < entry_count) { section = entries_address_ascending[i]->section; rc = fill_section_content(section, i, entry_count - 1); if (rc == OP_JIT_CONV_FAIL) goto out; } out: return rc; } /* create the elf file */ int open_elf(char * filename) { int rc = OP_JIT_CONV_OK; bfd_boolean r; cur_bfd = bfd_openw(filename, dump_bfd_target_name); if (cur_bfd == NULL) { bfd_perror("bfd_openw"); rc = OP_JIT_CONV_FAIL; goto out; } r = bfd_set_format(cur_bfd, bfd_object); if (r == FALSE) { bfd_perror("bfd_set_format"); rc = OP_JIT_CONV_FAIL; goto out; } r = bfd_set_arch_mach(cur_bfd, dump_bfd_arch, dump_bfd_mach); if (r == FALSE) { bfd_perror("bfd_set_format"); rc = OP_JIT_CONV_FAIL; goto out; } out: return rc; } --- NEW FILE: jitsymbol.c --- /** * @file jitsymbol.c * Handle symbols found in jitted code dump * * @remark Copyright 2007 OProfile authors * @remark Read the file COPYING * * @author Jens Wilke * @Modifications Maynard Johnson * @Modifications Philippe Elie * * Copyright IBM Corporation 2007 * */ #include "opjitconv.h" #include "opd_printf.h" #include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <limits.h> static void * op_jit_realloc(void * ptr, size_t sz) { void * tmp = realloc(ptr, sz); if (tmp == NULL) { printf("op_jit_realloc error\n"); /* The code in this file is intended to be excecuted as * as a forked child. */ _exit(EXIT_FAILURE); } return tmp; } /* count the entries in the jitentry_list */ static int count_entries() { int cnt = 0; struct jitentry * entry; entry = jitentry_list; while (entry != NULL) { entry = entry->next; cnt ++; } return cnt; } static void fill_entry_array(struct jitentry * entries[]) { int i = 0; struct jitentry * entry; entry = jitentry_list; while (entry != NULL) { entries[i++] = entry; entry = entry->next; } } /* create an array pointin to the jitentry structures which is sorted according * to the comparator rule given by parameter compar */ static struct jitentry ** create_sorted_array(int(*compar)(const void *, const void *)) { struct jitentry ** array = (struct jitentry **) op_jit_malloc(sizeof(struct jitentry *) * entry_count); fill_entry_array(array); qsort(array, entry_count, sizeof(struct jitentry *), compar); return array; } /* comparator method for qsort which sorts jitentries by symbol_name */ static int cmp_symbolname(const void * a, const void * b) { struct jitentry * a0 = *(struct jitentry **) a; struct jitentry * b0 = *(struct jitentry **) b; return strcmp(a0->symbol_name, b0->symbol_name); } /* comparator method for qsort which sorts jitentries by address */ static int cmp_address(const void * a, const void * b) { struct jitentry * a0 = *(struct jitentry **) a; struct jitentry * b0 = *(struct jitentry **) b; if (a0->code_addr < b0->code_addr) { return OP_JIT_CONV_FAIL; } if (a0->code_addr == b0->code_addr) { return 0; } return 1; } /* resort address_ascending array */ static void resort_address(void) { int i; qsort(entries_address_ascending, entry_count, sizeof(struct jitentry *), cmp_address); // lower entry_count if entries are invalidated i = 0; while( i < entry_count && entries_address_ascending[i]->code_addr == 0) { i++; } if (i > 0) { entry_count -= i; memmove( &entries_address_ascending[0], &entries_address_ascending[i], sizeof(struct jitentry *) * entry_count); } } /* Copy address_ascending array to entries_symbols_ascending and resort it. */ static void resort_symbol(void) { memcpy( entries_symbols_ascending, entries_address_ascending, sizeof(struct jitentry *) * entry_count); qsort(entries_symbols_ascending, entry_count, sizeof(struct jitentry *), cmp_symbolname); } /* allocate, populate and sort the jitentry arrays */ void create_arrays(void) { max_entry_count = entry_count = count_entries(); entries_symbols_ascending = create_sorted_array(cmp_symbolname); entries_address_ascending = create_sorted_array(cmp_address); } /* add a new create jitentry to the array. mallocs new arrys if space is needed */ static void insert_entry(struct jitentry * entry) { if (entry_count == max_entry_count) { max_entry_count += 18; entries_symbols_ascending = (struct jitentry **) op_jit_realloc(entries_symbols_ascending, sizeof(struct jitentry *) * max_entry_count); entries_address_ascending = (struct jitentry **) op_jit_realloc(entries_address_ascending, sizeof(struct jitentry *) * max_entry_count); } entries_address_ascending[entry_count++] = entry; } /* add a suffix to the name to differenciate it */ static char * replacement_name(char * s, int i) { int cnt = 1; int j = i; char * res; while ((j = j/10)) { cnt++; } cnt += 2 + strlen(s); res = (char *)op_jit_malloc(cnt); snprintf(res, cnt, "%s~%i", s, i); return res; } /* * Mark the entry so it is not included in the ELF file. We do this by * writing a 0 address as magic code_addr and sorting * it out later */ static void invalidate_entry(struct jitentry * e) { verbprintf(debug, "invalidate_entry: addr=%llx, name=%s\n", e->code_addr, e->symbol_name); e->code_addr = 0; } /* * Invalidate all symbols that are not alive at sampling start time. */ static void invalidate_earlybirds(unsigned long long start_time) { int i, flag; struct jitentry * a; flag = 0; for (i = 0; i < entry_count; i++) { a = entries_address_ascending[i]; if (a->life_end < start_time) { invalidate_entry(a); flag = 1; } } if (flag) { resort_address(); resort_symbol(); } } /* select the symbol with the longest life time in the index range */ static int select_one(int start_idx, int end_idx) { int i; int candidate = OP_JIT_CONV_FAIL; unsigned long long lifetime = 0; unsigned long long x; struct jitentry * e; for (i = start_idx; i <= end_idx; i++) { e = entries_address_ascending[i]; x =e->life_end - e->life_start; if (candidate == -1 || x > lifetime) { candidate = i; lifetime = x; } } return candidate; } /* * We decided to keep one entry in favor of the other. Instead of dropping * the overlapping entry we split or truncate it to not overlap any more. * * Looking on the address regions, we may have the following situation: * * split: |-------------| * keep: |-----| * * The split entry may be splitted in a left part and a right part. E.g.: * * split0/1: |--| |---| * keep: |---| * * However, both parts may or may not exist. */ static void split_entry(struct jitentry * split, struct jitentry * keep) { unsigned long long start_addr_keep = keep->code_addr; unsigned long long end_addr_keep = keep->code_addr + keep->code_size; unsigned long long end_addr_split = split->code_addr + split->code_size; unsigned long long start_addr_split = split->code_addr; // do we need a right part? if (end_addr_split > end_addr_keep) { struct jitentry * new_entry = malloc_jitentry(); char * s = (char *)op_jit_malloc(strlen(split->symbol_name) + 3); strcpy(s, split->symbol_name); strcat(s, "#1"); new_entry->code_addr = end_addr_keep; new_entry->code_size = end_addr_split - end_addr_keep; new_entry->symbol_name = s; new_entry ->sym_name_malloced = 1; new_entry->life_start = split->life_start; new_entry->life_end = split->life_end; // the right part does not have an associated code, because we // don't know whether the split part begins at an opcode new_entry->code = NULL; verbprintf(debug, "split right (new) name=%s, start=%llx," " end=%llx\n", new_entry->symbol_name, new_entry->code_addr, new_entry->code_addr + new_entry->code_size); insert_entry(new_entry); } // do we need a left part? if (start_addr_split < start_addr_keep) { char * s = (char *)op_jit_malloc(strlen(split->symbol_name) + 3); strcpy(s, split->symbol_name); strcat(s, "#0"); split->code_size = start_addr_keep - start_addr_split; if (split->sym_name_malloced) free(split->symbol_name); split->symbol_name = s; split->sym_name_malloced = 1; verbprintf(debug, "split left name=%s, start=%llx, end=%llx\n", split->symbol_name,split->code_addr, split->code_addr + split->code_size); } else { invalidate_entry(split); } } /* * Scans through the index range and invalidate entries that overlap * with the one indexed by keep_idx. Returns the total lifetime of the * symbols found to overlap. * Returns ULONG_MAX on error. */ static unsigned long long blank_overlaps(int start_idx, int end_idx, int keep_idx) { unsigned long long retval; struct jitentry * keep = entries_address_ascending[keep_idx]; struct jitentry * e; unsigned long long start_addr_keep = keep->code_addr; unsigned long long end_addr_keep = keep->code_addr + keep->code_size; unsigned long long start_addr_entry, end_addr_entry; int i; unsigned long long min_start = keep->life_start; unsigned long long max_end = keep->life_end; for (i = start_idx; i <= end_idx; i++) { if (i == keep_idx) { continue; } e = entries_address_ascending[i]; start_addr_entry = e->code_addr; end_addr_entry = e->code_addr + e->code_size; if (debug) { if (! (start_addr_entry <= end_addr_entry)) { verbprintf(debug, "assert failed:" " start_addr_entry <=" " end_addr_entry\n"); retval = ULONG_MAX; goto out; } if (! (start_addr_keep <= end_addr_keep)) { verbprintf(debug, "assert failed: " "start_addr_keep <=" " end_addr_keep\n"); retval = ULONG_MAX; goto out; } } if (start_addr_entry < end_addr_keep && end_addr_entry > start_addr_keep) { if (e->life_start < min_start) { min_start = e->life_start; } if (e->life_end > max_end) { max_end = e->life_end; } split_entry(e, keep); } } retval = max_end - min_start; out: return retval; } /* * Within the index range (into the array entries_address_ascending), find the * symbol with the maximal lifetime and blank out all symbols that overlap * with it. */ static int handle_overlap_region(int start_idx, int end_idx) { int rc = OP_JIT_CONV_OK; int idx; struct jitentry * e; int cnt; char * name; int i, j; unsigned long long totaltime; if (debug) { for (i = start_idx; i <= end_idx; i++) { e = entries_address_ascending[i]; verbprintf(debug, "overlap idx=%i, name=%s, " "start=%llx, end=%llx, life_start=%lli, " "life_end=%lli, lifetime=%lli\n", i, e->symbol_name, e->code_addr, e->code_addr + e->code_size, e->life_start, e->life_end, e->life_end - e->life_start); } } idx = select_one(start_idx, end_idx); totaltime = blank_overlaps(start_idx, end_idx, idx); if (totaltime == ULONG_MAX) { rc = OP_JIT_CONV_FAIL; goto out; } e = entries_address_ascending[idx]; cnt = 1; j = (e->life_end - e->life_start) * 100 / totaltime; while ((j = j/10)) { cnt++; } // Mark symbol name with a %% to indicate the overlap. cnt += strlen(e->symbol_name) + 2 + 1; name = (char *)op_jit_malloc(cnt); snprintf(name, cnt, "%s%%%llu", e->symbol_name, (e->life_end - e->life_start) * 100 / totaltime); if (e->sym_name_malloced) free(e->symbol_name); e->symbol_name = name; e->sym_name_malloced = 1; verbprintf(debug, "selected idx=%i, name=%s\n", idx, e->symbol_name); out: return rc; } /* * one scan through the symbols to find overlaps. * return 1 if an overlap is found. this is repeated until no more overlap * is there. * Process: There may be more than two overlapping symbols with each other. * The index range of symbols found to overlap are passed to * handle_overlap_region. */ static int scan_overlaps(void) { int i, j; unsigned long long end_addr, end_addr2; struct jitentry * a; struct jitentry * b; int flag = 0; // we add entries during this loop (in split_entry) and increment entry_count // save the inital value as loop count int loop_count = entry_count; verbprintf(debug,"count=%i, scan overlaps...\n", entry_count); i = j = 0; /* b: the entry before */ b = entries_address_ascending[i]; end_addr = b->code_addr + b->code_size; for (j++; j < loop_count; j++) { /* a: the actual entry */ a = entries_address_ascending[j]; if (end_addr <= a->code_addr) { if (i != j - 1) { if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL) { flag = OP_JIT_CONV_FAIL; goto out; } flag = 1; } i = j; } b = a; end_addr2 = b->code_addr + b->code_size; if (end_addr2 > end_addr) { end_addr = end_addr2; } } if (i != j - 1) { if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL) flag = OP_JIT_CONV_FAIL; else flag = 1; } out: return flag; } /* search for symbols that have overlapping address ranges and decide for one */ int resolve_overlaps(unsigned long long start_time) { int rc = OP_JIT_CONV_OK; int cnt = 0; invalidate_earlybirds(start_time); while((rc = scan_overlaps()) && rc != OP_JIT_CONV_FAIL) { resort_address(); if (cnt == 0) { verbprintf(debug, "WARNING: overlaps detected. " "Removing overlapping JIT methods\n"); } cnt++; } if (cnt > 0 && rc != OP_JIT_CONV_FAIL) { resort_symbol(); } return rc; } /* * scan through the sorted array and replace identical symbol names by unique ones * by adding a counter value. */ void disambiguate_symbol_names(void) { int i, j, cnt, rep_cnt; struct jitentry * a; struct jitentry * b; rep_cnt = 0; for (j = 1; j < entry_count; j++) { i = j - 1; a = entries_symbols_ascending[i]; cnt = 1; do { b = entries_symbols_ascending[j]; if (strcmp(a->symbol_name, b->symbol_name) == 0) { if (b->sym_name_malloced) free(b->symbol_name); b->symbol_name = replacement_name(b->symbol_name, cnt); b->sym_name_malloced = 1; j++; cnt++; rep_cnt++; } else { break; } } while (j < entry_count); } /* recurse to avoid that the added suffix also creates a collision */ if (rep_cnt > 0) { qsort(entries_symbols_ascending, entry_count, sizeof(struct jitentry *), cmp_symbolname); disambiguate_symbol_names(); } } --- NEW FILE: opjitconv.h --- /** * @file opjitconv.h * Convert a jit dump file to an ELF file * * @remark Copyright 2007 OProfile authors * @remark Read the file COPYING * * @author Jens Wilke * @Modifications Maynard Johnson * @Modifications Philippe Elie * * Copyright IBM Corporation 2007 * */ #ifndef OPJITCONV_H #define OPJITCONV_H #define OP_JIT_CONV_OK 0 #define OP_JIT_CONV_FAIL -1 /* FIXME: remove it */ typedef void * PTR; #include <bfd.h> #include <stddef.h> /* Structure that contains all information * for one function entry in the jit dump file. * the jit dump file gets mmapped and code and * symbol_name point directly into the file */ struct jitentry { /* linked list. see jitentry_list */ struct jitentry * next; /* vma */ unsigned long long code_addr; /* point to code in the memory mapped file */ void * code; /* size of the jitted code */ int code_size; /* point to the name in memory mapped jitdump file, or * to a malloced string, if we have a disambiguation replacement */ char * symbol_name; /* sym_name_malloced ==1 means we need to free the memory when done. */ int sym_name_malloced; /* seconds since epoch when the code was created */ unsigned long long life_start; /* seconds since epoch when the code was overwritten */ unsigned long long life_end; /* after ordering and partiioning this is the ELF * section we put this code to */ asection * section; }; void * op_jit_malloc(size_t sz); struct jitentry * malloc_jitentry(void); /* jitsymbol.c */ void create_arrays(void); int resolve_overlaps(unsigned long long start_time); void disambiguate_symbol_names(void); /* parse_dump.c */ int parse_all(PTR start, PTR end, unsigned long long end_time); /* create_bfd.c */ int open_elf(char * filename); int partition_sections(); int fill_sections(); /* jit dump header information */ extern enum bfd_architecture dump_bfd_arch; extern int dump_bfd_mach; extern char * dump_bfd_target_name; /* * list head. The linked list is used during parsing (parse_all) to * hold all jitentry elements. After parsing, the program works on the * array structures (entries_symbols_ascending, entries_address_ascending) * and the linked list is not used any more. */ extern struct jitentry * jitentry_list; /* count of jitentries in the list */ extern int entry_count; /* maximul space in the entry arrays, needed to add entries */ extern int max_entry_count; /* array pointing to all jit entries, sorted by symbol names */ extern struct jitentry ** entries_symbols_ascending; /* array pointing to all jit entries sorted by address */ extern struct jitentry ** entries_address_ascending; /* Global variable for asymbols so we can free the storage later. */ extern asymbol ** syms; /* the bfd handle of the ELF file we write */ extern bfd * cur_bfd; /* debug flag, print some information */ extern int debug; #endif /* OPJITCONV_H */ --- NEW FILE: parse_dump.c --- /** * @file parse_dump.c * parse a jit dump file * * @remark Copyright 2007 OProfile authors * @remark Read the file COPYING * * @author Jens Wilke * @Modifications Maynard Johnson * @Modifications Philippe Elie * * Copyright IBM Corporation 2007 * */ #include "opjitconv.h" #include "jitdump.h" #include "opd_printf.h" #include <string.h> #include <stdio.h> /* parse a type 0 record (code load) and add the entry to the jitentry list */ static int parse_record0(PTR ptr_arg, int size, unsigned long long end_time) { struct jitentry * entry; int rc = OP_JIT_CONV_OK; char * ptr = (char *)ptr_arg; struct jitrecord0 * rec = (struct jitrecord0 *) ptr_arg; char * end = ptr + size; entry = malloc_jitentry(); // jitentry constructor entry->next = NULL; ptr += sizeof(*rec); entry->symbol_name = ptr; ptr += strlen(ptr) + 1; entry->code = ptr; entry->code_addr = rec->code_addr; entry->code_size = rec->code_size; entry->section = NULL; entry->life_start = rec->timestamp; // if nothing else is known the symbol lifes till the end of the // sampling run, this value may be overwritten by an unload record1 // later entry->life_end = end_time; // build list entry->next = jitentry_list; jitentry_list = entry; verbprintf(debug, "record0: name=%s, code_addr=%llx, code_size=%i, " "life_start=%lli, life_end=%lli\n", entry->symbol_name, entry->code_addr, entry->code_size, entry->life_start, entry->life_end); if ((ptr + entry->code_size) != end) { verbprintf(debug, "length mismatch"); rc = OP_JIT_CONV_FAIL; } return rc; } /* * parse type 1 record (unload). search for existing jitrecord with this code * address and fill life_end field with the timestamp. linear search not very * efficient. */ static void parse_record1(PTR ptr, unsigned long long end_time) { struct jitrecord1 * rec = (struct jitrecord1 *) ptr; struct jitentry * entry; verbprintf(debug,"record1: code_addr=%llx, life_end=%lli\n", rec->code_addr, rec->timestamp); if (rec->timestamp > 0 && rec->code_addr != 0) { entry = jitentry_list; while (entry) { if (entry->code_addr == rec->code_addr && entry->life_end == end_time) { entry->life_end = rec->timestamp; verbprintf(debug,"matching record found\n"); break; } entry = entry->next; } } } /* parse all entries in the jit dump file and build jitentry_list. * the code needs to check always whether there is enough * to read remaining. this is because the file may be written to * concurrently. */ static int parse_entries(PTR ptr, PTR end, unsigned long long end_time) { int rc = OP_JIT_CONV_OK; struct jitrecord * rec = (struct jitrecord *)ptr; while (((PTR) rec) + sizeof(struct jitrecord) < end) { if (((PTR) rec + rec->total_size) <= end) { if (rec->id == 0) { if (parse_record0((PTR) rec, rec->total_size, end_time)) { rc = OP_JIT_CONV_FAIL; break; } } else if (rec->id == 1) { parse_record1((PTR) rec, end_time); } else if (rec->id == 2) { // end of VM live time, no action } else { verbprintf(debug, "unknown record type\n"); rc = OP_JIT_CONV_FAIL; break; } } rec = (struct jitrecord *) ((PTR) rec + rec->total_size); } return rc; } /* parse the jit dump header information * The ptr arg is the address of the pointer to the mmapped * file, which we modify below. */ static int parse_header(char ** ptr, char * end) { int rc = OP_JIT_CONV_OK; struct jitheader * header; if (end - *ptr <= (int)sizeof(struct jitheader)) { verbprintf(debug, "opjitconv: EOF in jitdump file, no header\n"); rc = OP_JIT_CONV_FAIL; goto out; } header = (struct jitheader *) *ptr; if (header->magic != JITHEADER_MAGIC) { verbprintf(debug, "opjitconv: Wrong jitdump file magic\n"); rc = OP_JIT_CONV_FAIL; goto out; } if (header->version != JITHEADER_VERSION) { verbprintf(debug, "opjitconv: Wrong jitdump file version\n"); rc = OP_JIT_CONV_FAIL; goto out; } dump_bfd_arch = header->bfd_arch; dump_bfd_mach = header->bfd_mach; dump_bfd_target_name = header->bfd_target; verbprintf(debug, "header: bfd-arch=%i, bfd-mach=%i," " bfd_target_name=%s\n", dump_bfd_arch, dump_bfd_mach, dump_bfd_target_name); *ptr = *ptr + header->totalsize; out: return rc; } /* Read in the memory mapped jitdump file. * Build up jitentry structure and set global variables. */ int parse_all(PTR start, PTR end, unsigned long long end_time) { char * ptr = (char *)start; if (!parse_header(&ptr, (char *)end)) return parse_entries(ptr, end, end_time); else return OP_JIT_CONV_FAIL; } Index: Makefile.am =================================================================== RCS file: /cvsroot/oprofile/oprofile/opjitconv/Attic/Makefile.am,v retrieving revision 1.1.2.4 retrieving revision 1.1.2.5 diff -u -p -d -r1.1.2.4 -r1.1.2.5 --- Makefile.am 16 Nov 2007 16:08:53 -0000 1.1.2.4 +++ Makefile.am 17 Nov 2007 15:26:31 -0000 1.1.2.5 @@ -10,4 +10,9 @@ needed_libs = \ opjitconv_LDADD = $(needed_libs) -opjitconv_SOURCES = opjitconv.c +opjitconv_SOURCES = \ + opjitconv.c \ + opjitconv.h \ + parse_dump.c \ + jitsymbol.c \ + create_bfd.c Index: opjitconv.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/opjitconv/Attic/opjitconv.c,v retrieving revision 1.1.2.7 retrieving revision 1.1.2.8 diff -u -p -d -r1.1.2.7 -r1.1.2.8 --- opjitconv.c 16 Nov 2007 16:08:53 -0000 1.1.2.7 +++ opjitconv.c 17 Nov 2007 15:26:31 -0000 1.1.2.8 @@ -12,7 +12,7 @@ * */ -#include "jitdump.h" +#include "opjitconv.h" #include "opd_printf.h" #include "op_file.h" #include "op_list.h" @@ -34,8 +34,6 @@ #define MAX_OUTPUT_LINES 10 -#define OP_JIT_CONV_OK 0 -#define OP_JIT_CONV_FAIL -1 #define OP_JIT_CONV_NO_DUMPFILE 1 #define OP_JIT_CONV_NO_MATCHING_ANON_SAMPLES 2 #define OP_JIT_CONV_NO_JIT_RECS_IN_DUMPFILE 3 @@ -51,66 +49,38 @@ struct pathname { struct list_head neighbor; }; -/* Structure that contains all information - * for one function entry in the jit dump file. - * the jit dump file gets mmapped and code and - * symbol_name point directly into the file */ -struct jitentry { - /* linked list. see jitentry_list */ - struct jitentry * next; - /* vma */ - unsigned long long code_addr; - /* point to code in the memory mapped file */ - void * code; - /* size of the jitted code */ - int code_size; - /* point to the name in memory mapped jitdump file, or - * to a malloced string, if we have a disambiguation replacement */ - char * symbol_name; - /* sym_name_malloced ==1 means we need to free the memory when done. */ - int sym_name_malloced; - /* seconds since epoch when the code was created */ - unsigned long long life_start; - /* seconds since epoch when the code was overwritten */ - unsigned long long life_end; - /* after ordering and partiioning this is the ELF - * section we put this code to */ - asection * section; -}; - /* * list head. The linked list is used during parsing (parse_all) to * hold all jitentry elements. After parsing, the program works on the * array structures (entries_symbols_ascending, entries_address_ascending) * and the linked list is not used any more. */ -static struct jitentry * jitentry_list = NULL; +struct jitentry * jitentry_list = NULL; /* Global variable for asymbols so we can free the storage later. */ -static asymbol ** syms; +asymbol ** syms; /* jit dump header information */ -static enum bfd_architecture dump_bfd_arch; -static int dump_bfd_mach; -static char * dump_bfd_target_name; +enum bfd_architecture dump_bfd_arch; +int dump_bfd_mach; +char * dump_bfd_target_name; /* the bfd handle of the ELF file we write */ -static bfd * cur_bfd; +bfd * cur_bfd; /* count of jitentries in the list */ -static int entry_count; +int entry_count; /* maximul space in the entry arrays, needed to add entries */ -static int max_entry_count; +int max_entry_count; /* array pointing to all jit entries, sorted by symbol names */ -static struct jitentry ** entries_symbols_ascending; +struct jitentry ** entries_symbols_ascending; /* array pointing to all jit entries sorted by address */ -static struct jitentry ** entries_address_ascending; +struct jitentry ** entries_address_ascending; /* debug flag, print some information */ -static int debug; - +int debug; -static void * op_jit_malloc(size_t sz) +void * op_jit_malloc(size_t sz) { void * tmp = malloc(sz); if (tmp == NULL) { @@ -123,19 +93,6 @@ static void * op_jit_malloc(size_t sz) return tmp; } -static void * op_jit_realloc(void * ptr, size_t sz) -{ - void * tmp = realloc(ptr, sz); - if (tmp == NULL) { - printf("op_jit_realloc error\n"); - /* The code in this file is intended to be excecuted as - * as a forked child. - */ - _exit(EXIT_FAILURE); - } - return tmp; -} - struct jitentry * malloc_jitentry() { struct jitentry * entry; @@ -146,848 +103,6 @@ struct jitentry * malloc_jitentry() return entry; } -/* - ********************************************************* parse JIT-Dump file - */ - -/* parse a type 0 record (code load) and add the entry to the jitentry list */ -static int parse_record0(PTR ptr_arg, int size, unsigned long long end_time) -{ - struct jitentry * entry; - int rc = OP_JIT_CONV_OK; - char * ptr = (char *)ptr_arg; - struct jitrecord0 * rec = (struct jitrecord0 *) ptr_arg; - char * end = ptr + size; - entry = malloc_jitentry(); - // jitentry constructor - entry->next = NULL; - ptr += sizeof(*rec); - entry->symbol_name = ptr; - ptr += strlen(ptr) + 1; - entry->code = ptr; - entry->code_addr = rec->code_addr; - entry->code_size = rec->code_size; - entry->section = NULL; - entry->life_start = rec->timestamp; - // if nothing else is known the symbol lifes till the end of the - // sampling run, this value may be overwritten by an unload record1 later - entry->life_end = end_time; - // build list - entry->next = jitentry_list; - jitentry_list = entry; - verbprintf(debug,"record0: name=%s, code_addr=%llx, code_size=%i," - " life_start=%lli, life_end=%lli\n", entry->symbol_name, - entry->code_addr, entry->code_size, entry->life_start, - entry->life_end); - if ((ptr + entry->code_size) != end) { - verbprintf(debug,"length mismatch"); - rc = OP_JIT_CONV_FAIL; - } - return rc; -} - -/* - * parse type 1 record (unload). search for existing jitrecord with this code - * address and fill life_end field with the timestamp. linear search not very - * efficient. - */ -static void parse_record1(PTR ptr, unsigned long long end_time) -{ - struct jitrecord1 * rec = (struct jitrecord1 *) ptr; - struct jitentry * entry; - - verbprintf(debug,"record1: code_addr=%llx, life_end=%lli\n", - rec->code_addr, rec->timestamp); - if (rec->timestamp > 0 && rec->code_addr != 0) { - entry = jitentry_list; - while (entry) { - if (entry->code_addr == rec->code_addr && - entry->life_end == end_time) { - entry->life_end = rec->timestamp; - verbprintf(debug,"matching record found\n"); - break; - } - entry = entry->next; - } - } -} - -/* parse all entries in the jit dump file and build jitentry_list. - * the code needs to check always whether there is enough - * to read remaining. this is because the file may be written to - * concurrently. */ -static int parse_entries(PTR ptr, PTR end, unsigned long long end_time) -{ - int rc = OP_JIT_CONV_OK; - struct jitrecord * rec = (struct jitrecord *)ptr; - - while (((PTR) rec) + sizeof(struct jitrecord) < end) { - if (((PTR) rec + rec->total_size) <= end) { - if (rec->id == 0) { - if (parse_record0((PTR) rec, rec->total_size, - end_time)) { - rc = OP_JIT_CONV_FAIL; - break; - } - } else if (rec->id == 1) { - parse_record1((PTR) rec, end_time); - } else if (rec->id == 2) { - // end of VM live time, no action - } else { - verbprintf(debug, "unknown record type\n"); - rc = OP_JIT_CONV_FAIL; - break; - } - } - rec = (struct jitrecord *) ((PTR) rec + rec->total_size); - } - return rc; -} - -/* parse the jit dump header information - * The ptr arg is the address of the pointer to the mmapped - * file, which we modify below. -*/ -static int parse_header(char ** ptr, char * end) -{ - int rc = OP_JIT_CONV_OK; - struct jitheader * header; - - if (end - *ptr <= (int)sizeof(struct jitheader)) { - verbprintf(debug, "opjitconv: EOF in jitdump file, no header\n"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - header = (struct jitheader *) *ptr; - if (header->magic != JITHEADER_MAGIC) { - verbprintf(debug, "opjitconv: Wrong jitdump file magic\n"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - if (header->version != JITHEADER_VERSION) { - verbprintf(debug, "opjitconv: Wrong jitdump file version\n"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - dump_bfd_arch = header->bfd_arch; - dump_bfd_mach = header->bfd_mach; - dump_bfd_target_name = header->bfd_target; - verbprintf(debug, "header: bfd-arch=%i, bfd-mach=%i," - " bfd_target_name=%s\n", dump_bfd_arch, dump_bfd_mach, - dump_bfd_target_name); - *ptr = *ptr + header->totalsize; - out: - return rc; -} - -/* Read in the memory mapped jitdump file. - * Build up jitentry structure and set global variables. -*/ -static int parse_all(PTR start, PTR end, unsigned long long end_time) -{ - char * ptr = (char *)start; - if (!parse_header(&ptr, (char *)end)) - return parse_entries(ptr, end, end_time); - else - return OP_JIT_CONV_FAIL; -} - -/* - ****************************************** sort symbols and disambiguate names - */ - -/* count the entries in the jitentry_list */ -static int count_entries() -{ - int cnt = 0; - struct jitentry * entry; - entry = jitentry_list; - while (entry!=NULL) { - entry = entry->next; - cnt ++; - } - return cnt; -} - -static void fill_entry_array(struct jitentry * entries[]) -{ - int i = 0; - struct jitentry * entry; - entry = jitentry_list; - - while (entry!=NULL) { - entries[i++] = entry; - entry = entry->next; - } -} - -/* create an array pointin to the jitentry structures which is sorted according - * to the comparator rule given by parameter compar */ -static struct jitentry ** create_sorted_array(int(*compar)(const void *, const void *)) -{ - struct jitentry ** array = (struct jitentry **) - op_jit_malloc(sizeof(struct jitentry *) * entry_count); - fill_entry_array(array); - qsort(array, entry_count, sizeof(struct jitentry *), compar); - return array; - } - -/* comparator method for qsort which sorts jitentries by symbol_name */ -static int cmp_symbolname(const void * a, const void * b) -{ - struct jitentry * a0 = *(struct jitentry **) a; - struct jitentry * b0 = *(struct jitentry **) b; - return strcmp(a0->symbol_name, b0->symbol_name); -} - -/* comparator method for qsort which sorts jitentries by address */ -static int cmp_address(const void * a, const void * b) -{ - struct jitentry * a0 = *(struct jitentry **) a; - struct jitentry * b0 = *(struct jitentry **) b; - if (a0->code_addr < b0->code_addr) { - return OP_JIT_CONV_FAIL; - } - if (a0->code_addr == b0->code_addr) { - return 0; - } - return 1; -} - -/* resort address_ascending array */ -static void resort_address(void) -{ - int i; - - qsort(entries_address_ascending, entry_count, sizeof(struct jitentry *), cmp_address); - // lower entry_count if entries are invalidated - i = 0; - while( i < entry_count && entries_address_ascending[i]->code_addr == 0) { - i++; - } - if (i > 0) { - entry_count -= i; - memmove( - &entries_address_ascending[0], - &entries_address_ascending[i], - sizeof(struct jitentry *) * entry_count); - } -} - -/* Copy address_ascending array to entries_symbols_ascending and resort it. */ -static void resort_symbol(void) -{ - memcpy( - entries_symbols_ascending, - entries_address_ascending, - sizeof(struct jitentry *) * entry_count); - qsort(entries_symbols_ascending, entry_count, sizeof(struct jitentry *), cmp_symbolname); -} - -/* allocate, populate and sort the jitentry arrays */ -static void create_arrays(void) -{ - max_entry_count = entry_count = count_entries(); - entries_symbols_ascending = create_sorted_array(cmp_symbolname); - entries_address_ascending = create_sorted_array(cmp_address); -} - -/* add a new create jitentry to the array. mallocs new arrys if space is needed */ -static void insert_entry(struct jitentry * entry) -{ - if (entry_count == max_entry_count) { - max_entry_count += 18; - entries_symbols_ascending = (struct jitentry **) - op_jit_realloc(entries_symbols_ascending, - sizeof(struct jitentry *) * - max_entry_count); - entries_address_ascending = (struct jitentry **) - op_jit_realloc(entries_address_ascending, - sizeof(struct jitentry *) * - max_entry_count); - } - entries_address_ascending[entry_count++] = entry; -} - -/* add a suffix to the name to differenciate it */ -static char * replacement_name(char * s, int i) -{ - int cnt = 1; - int j = i; - char * res; - - while ((j = j/10)) { - cnt++; - } - cnt += 2 + strlen(s); - res = (char *)op_jit_malloc(cnt); - snprintf(res, cnt, "%s~%i", s, i); - return res; -} - -/* - * Mark the entry so it is not included in the ELF file. We do this by - * writing a 0 address as magic code_addr and sorting - * it out later - */ -static void invalidate_entry(struct jitentry * e) -{ - verbprintf(debug, "invalidate_entry: addr=%llx, name=%s\n", - e->code_addr, e->symbol_name); - e->code_addr = 0; -} - -/* - * Invalidate all symbols that are not alive at sampling start time. - */ -static void invalidate_earlybirds(unsigned long long start_time) -{ - int i, flag; - struct jitentry * a; - - flag = 0; - for (i = 0; i < entry_count; i++) { - a = entries_address_ascending[i]; - if (a->life_end < start_time) { - invalidate_entry(a); - flag = 1; - } - } - if (flag) { - resort_address(); - resort_symbol(); - } -} - -/* select the symbol with the longest life time in the index range */ -static int select_one(int start_idx, int end_idx) -{ - int i; - int candidate = OP_JIT_CONV_FAIL; - unsigned long long lifetime = 0; - unsigned long long x; - struct jitentry * e; - - for (i = start_idx; i <= end_idx; i++) { - e = entries_address_ascending[i]; - x =e->life_end - e->life_start; - if (candidate == -1 || x > lifetime) { - candidate = i; - lifetime = x; - } - } - return candidate; -} - -/* - * We decided to keep one entry in favor of the other. Instead of dropping - * the overlapping entry we split or truncate it to not overlap any more. - * - * Looking on the address regions, we may have the following situation: - * - * split: |-------------| - * keep: |-----| - * - * The split entry may be splitted in a left part and a right part. E.g.: - * - * split0/1: |--| |---| - * keep: |---| - * - * However, both parts may or may not exist. - */ -static void split_entry(struct jitentry * split, struct jitentry * keep) -{ - unsigned long long start_addr_keep = keep->code_addr; - unsigned long long end_addr_keep = keep->code_addr + keep->code_size; - unsigned long long end_addr_split = split->code_addr + split->code_size; - unsigned long long start_addr_split = split->code_addr; - - // do we need a right part? - if (end_addr_split > end_addr_keep) { - struct jitentry * new_entry = malloc_jitentry(); - char * s = (char *)op_jit_malloc(strlen(split->symbol_name) - + 3); - strcpy(s, split->symbol_name); - strcat(s, "#1"); - new_entry->code_addr = end_addr_keep; - new_entry->code_size = end_addr_split - end_addr_keep; - new_entry->symbol_name = s; - new_entry ->sym_name_malloced = 1; - new_entry->life_start = split->life_start; - new_entry->life_end = split->life_end; - // the right part does not have an associated code, because we - // don't know whether the split part begins at an opcode - new_entry->code = NULL; - verbprintf(debug, "split right (new) name=%s, start=%llx," - " end=%llx\n", new_entry->symbol_name, - new_entry->code_addr, - new_entry->code_addr + new_entry->code_size); - insert_entry(new_entry); - } - // do we need a left part? - if (start_addr_split < start_addr_keep) { - char * s = (char *)op_jit_malloc(strlen(split->symbol_name) - + 3); - strcpy(s, split->symbol_name); - strcat(s, "#0"); - split->code_size = start_addr_keep - start_addr_split; - if (split->sym_name_malloced) - free(split->symbol_name); - split->symbol_name = s; - split->sym_name_malloced = 1; - verbprintf(debug, "split left name=%s, start=%llx, end=%llx\n", - split->symbol_name,split->code_addr, - split->code_addr + split->code_size); - } else { - invalidate_entry(split); - } -} - -/* - * Scans through the index range and invalidate entries that overlap - * with the one indexed by keep_idx. Returns the total lifetime of the - * symbols found to overlap. - * Returns ULONG_MAX on error. - */ -static unsigned long long blank_overlaps(int start_idx, int end_idx, int keep_idx) -{ - unsigned long long retval; - struct jitentry * keep = entries_address_ascending[keep_idx]; - struct jitentry * e; - unsigned long long start_addr_keep = keep->code_addr; - unsigned long long end_addr_keep = keep->code_addr + keep->code_size; - unsigned long long start_addr_entry, end_addr_entry; - int i; - unsigned long long min_start = keep->life_start; - unsigned long long max_end = keep->life_end; - - for (i = start_idx; i <= end_idx; i++) { - if (i == keep_idx) { - continue; - } - e = entries_address_ascending[i]; - start_addr_entry = e->code_addr; - end_addr_entry = e->code_addr + e->code_size; - if (debug) { - if (! (start_addr_entry <= end_addr_entry)) { - verbprintf(debug, "assert failed:" - " start_addr_entry <=" - " end_addr_entry\n"); - retval = ULONG_MAX; - goto out; - } - if (! (start_addr_keep <= end_addr_keep)) { - verbprintf(debug, "assert failed: " - "start_addr_keep <=" - " end_addr_keep\n"); - retval = ULONG_MAX; - goto out; - } - } - if (start_addr_entry < end_addr_keep && - end_addr_entry > start_addr_keep) { - if (e->life_start < min_start) { - min_start = e->life_start; - } - if (e->life_end > max_end) { - max_end = e->life_end; - } - split_entry(e, keep); - } - } - retval = max_end - min_start; - out: - return retval; -} - -/* - * Within the index range (into the array entries_address_ascending), find the - * symbol with the maximal lifetime and blank out all symbols that overlap - * with it. - */ -static int handle_overlap_region(int start_idx, int end_idx) -{ - int rc = OP_JIT_CONV_OK; - int idx; - struct jitentry * e; - int cnt; - char * name; - int i, j; - unsigned long long totaltime; - - if (debug) { - for (i = start_idx; i <= end_idx; i++) { - e = entries_address_ascending[i]; - verbprintf(debug, "overlap idx=%i, name=%s, " - "start=%llx, end=%llx, life_start=%lli, " - "life_end=%lli, lifetime=%lli\n", - i, e->symbol_name, e->code_addr, - e->code_addr + e->code_size, e->life_start, - e->life_end, e->life_end - e->life_start); - } - } - idx = select_one(start_idx, end_idx); - totaltime = blank_overlaps(start_idx, end_idx, idx); - if (totaltime == ULONG_MAX) { - rc = OP_JIT_CONV_FAIL; - goto out; - } - e = entries_address_ascending[idx]; - - cnt = 1; - j = (e->life_end - e->life_start) * 100 / totaltime; - while ((j = j/10)) { - cnt++; - } - // Mark symbol name with a %% to indicate the overlap. - cnt += strlen(e->symbol_name) + 2 + 1; - name = (char *)op_jit_malloc(cnt); - snprintf(name, cnt, "%s%%%llu", e->symbol_name, - (e->life_end - e->life_start) * 100 / totaltime); - if (e->sym_name_malloced) - free(e->symbol_name); - e->symbol_name = name; - e->sym_name_malloced = 1; - verbprintf(debug, "selected idx=%i, name=%s\n", idx, e->symbol_name); - out: - return rc; -} - -/* - * one scan through the symbols to find overlaps. - * return 1 if an overlap is found. this is repeated until no more overlap - * is there. - * Process: There may be more than two overlapping symbols with each other. - * The index range of symbols found to overlap are passed to - * handle_overlap_region. - */ -static int scan_overlaps(void) -{ - int i, j; - unsigned long long end_addr, end_addr2; - struct jitentry * a; - struct jitentry * b; - int flag = 0; - // we add entries during this loop (in split_entry) and increment entry_count - // save the inital value as loop count - int loop_count = entry_count; - - verbprintf(debug,"count=%i, scan overlaps...\n", entry_count); - i = j = 0; - /* b: the entry before */ - b = entries_address_ascending[i]; - end_addr = b->code_addr + b->code_size; - for (j++; j < loop_count; j++) { - /* a: the actual entry */ - a = entries_address_ascending[j]; - if (end_addr <= a->code_addr) { - if (i != j - 1) { - if (handle_overlap_region(i, j - 1) == - OP_JIT_CONV_FAIL) { - flag = OP_JIT_CONV_FAIL; - goto out; - } - flag = 1; - } - i = j; - } - b = a; - end_addr2 = b->code_addr + b->code_size; - if (end_addr2 > end_addr) { - end_addr = end_addr2; - } - } - if (i != j - 1) { - if (handle_overlap_region(i, j - 1) == OP_JIT_CONV_FAIL) - flag = OP_JIT_CONV_FAIL; - else - flag = 1; - } - out: - return flag; -} - -/* search for symbols that have overlapping address ranges and decide for one */ -static int resolve_overlaps(unsigned long long start_time) -{ - int rc = OP_JIT_CONV_OK; - int cnt = 0; - - invalidate_earlybirds(start_time); - while((rc = scan_overlaps()) && rc != OP_JIT_CONV_FAIL) { - resort_address(); - if (cnt == 0) { - verbprintf(debug, "WARNING: overlaps detected. " - "Removing overlapping JIT methods\n"); - } - cnt++; - } - if (cnt > 0 && rc != OP_JIT_CONV_FAIL) { - resort_symbol(); - } - return rc; -} - -/* - * scan through the sorted array and replace identical symbol names by unique ones - * by adding a counter value. - */ -static void disambiguate_symbol_names(void) -{ - int i, j, cnt, rep_cnt; - struct jitentry * a; - struct jitentry * b; - - rep_cnt = 0; - for (j = 1; j < entry_count; j++) { - i = j - 1; - a = entries_symbols_ascending[i]; - cnt = 1; - do { - b = entries_symbols_ascending[j]; - if (strcmp(a->symbol_name, b->symbol_name) == 0) { - if (b->sym_name_malloced) - free(b->symbol_name); - b->symbol_name = - replacement_name(b->symbol_name, cnt); - b->sym_name_malloced = 1; - j++; - cnt++; - rep_cnt++; - } else { - break; - } - } while (j < entry_count); - } - /* recurse to avoid that the added suffix also creates a collision */ - if (rep_cnt > 0) { - qsort(entries_symbols_ascending, entry_count, - sizeof(struct jitentry *), cmp_symbolname); - disambiguate_symbol_names(); - } -} - -/* - ******************************************************** create&write ELF file - */ - -/* Create the symbols and fill the syms array for all functions - * from start_idx to end_idx pointing into entries_address_ascending array */ -static int fill_symtab() -{ - int rc = OP_JIT_CONV_OK; - int i, r; - struct jitentry * e; - asymbol * s; - asection * section = NULL; - - syms = (asymbol **)op_jit_malloc(sizeof(asymbol *) * (entry_count+1)); - syms[entry_count] = NULL; - for (i = 0; i < entry_count; i++) { - e = entries_address_ascending[i]; - if (e->section) { - section = e->section; - } - s = bfd_make_empty_symbol(cur_bfd); - if (s == NULL) { - bfd_perror("bfd_make_empty_symbol"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - s->name = e->symbol_name; - s->section = section; - s->flags = BSF_GLOBAL | BSF_FUNCTION; - s->value = e->code_addr - section->vma; - verbprintf(debug,"add sym: name=%s, value=%llx\n", s->name, - s->value); - syms[i] = s; - } - r = bfd_set_symtab(cur_bfd, syms, entry_count); - if (r == FALSE) { - bfd_perror("bfd_set_symtab"); - rc = OP_JIT_CONV_FAIL; - goto out; - - } - out: - return rc; -} - -/* create the .text section. end_idx: index last jitentry (inclusive!) */ -static int create_section(int start_idx, int end_idx) { - int rc = OP_JIT_CONV_OK; - asection * section; - char * section_name; - int r; - int idx = start_idx; - unsigned long long vma_start = entries_address_ascending[start_idx]->code_addr; - struct jitentry * ee = entries_address_ascending[end_idx]; - unsigned long long vma_end = ee->code_addr + ee->code_size; - int size = vma_end - vma_start; - - section_name = - bfd_get_unique_section_name(cur_bfd, ".text", &idx); - verbprintf(debug, "section idx=%i, name=%s, vma_start=%llx, size=%i\n", - idx, section_name, vma_start, size); - section = bfd_make_section(cur_bfd, section_name); - if (section == NULL) { - bfd_perror("bfd_make_section"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - entries_address_ascending[start_idx]->section = section; - r = bfd_set_section_size(cur_bfd, section, size); - if (r == FALSE) { - bfd_perror("bfd_set_section_size"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - r = bfd_set_section_vma(cur_bfd, section, vma_start); - if (r == FALSE) { - bfd_perror("bfd_set_section_vma"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - r = bfd_set_section_flags(cur_bfd, section, - SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_HAS_CONTENTS); - if (r == FALSE) { - bfd_perror("bfd_set_section_flags"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - out: - return rc; -} - -/* - * Copy all code of the functions that are within start_idx and end_idx to - * the section. - */ -static int fill_section_content(asection * section, int start_idx, int end_idx) { - int rc = OP_JIT_CONV_OK; - unsigned long long vma_start = entries_address_ascending[start_idx]-> - code_addr; - struct jitentry * e; - bfd_boolean r; - int i; - - for (i = start_idx; i <= end_idx; i++) { - e = entries_address_ascending[i]; - verbprintf(debug, "section = %s, i = %i, code = %llx," - " code_addr = %llx, offset = %llx," - "size = %i, name = %s\n", - section->name, i, - (unsigned long long) (uintptr_t) e->code, - e->code_addr, e->code_addr - vma_start, - e->code_size, e->symbol_name); - /* the right part that is created by split_entry may - * hav no code. - */ - if (e->code != NULL) { - r = bfd_set_section_contents( - cur_bfd, section, - e->code, (file_ptr) (e->code_addr - vma_start), - (bfd_size_type) e->code_size); - if (r == FALSE) { - bfd_perror("bfd_set_section_contents"); - rc = OP_JIT_CONV_FAIL; - break; - } - } - } - return rc; -} - -/* Walk over the symbols sorted by address and create ELF sections. Whenever we - * have a gap greater or equal to 4096 make a new section. - */ -static int partition_sections() { - int rc = OP_JIT_CONV_OK; - int i, j; - struct jitentry * pred; - struct jitentry * entry; - unsigned long long end_addr; - - // i: start index of the section - i = 0; - pred = entries_address_ascending[i]; - for (j = i + 1; j < entry_count; j++) { - entry = entries_address_ascending[j]; - end_addr = pred->code_addr + pred->code_size; - // calculate gap between code, if it is more than one page - // create an additional section - if ( (entry->code_addr - end_addr) >= 4096) { - rc = create_section(i, j - 1); - if (rc == OP_JIT_CONV_FAIL) - goto out; - i = j; - } - pred = entry; - } - // this holds always if we have at least one jitentry - if (i < entry_count) { - rc = create_section(i, entry_count - 1); - } - out: - return rc; -} - -/* Fill the code content into the sections created by split_sections */ -static int fill_sections() { - int rc = OP_JIT_CONV_OK; - int i, j; - asection * section; - - rc = fill_symtab(); - if (rc == OP_JIT_CONV_FAIL) - goto out; - i = 0; - for (j = i + 1; j < entry_count; j++) { - if (entries_address_ascending[j]->section != NULL) { - section = entries_address_ascending[i]->section; - rc = fill_section_content(section, i, j - 1); - if (rc == OP_JIT_CONV_FAIL) - goto out; - i = j; - } - } - if (i < entry_count) { - section = entries_address_ascending[i]->section; - rc = fill_section_content(section, i, entry_count - 1); - if (rc == OP_JIT_CONV_FAIL) - goto out; - } - out: - return rc; -} - -/* create the elf file */ -static int open_elf(char * filename) { - int rc = OP_JIT_CONV_OK; - bfd_boolean r; - - cur_bfd = bfd_openw(filename, dump_bfd_target_name); - if (cur_bfd == NULL) { - bfd_perror("bfd_openw"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - r = bfd_set_format(cur_bfd, bfd_object); - if (r == FALSE) { - bfd_perror("bfd_set_format"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - r = bfd_set_arch_mach(cur_bfd, dump_bfd_arch, dump_bfd_mach); - if (r == FALSE) { - bfd_perror("bfd_set_format"); - rc = OP_JIT_CONV_FAIL; - goto out; - } - out: - return rc; -} - static void free_jit_records(void) { struct jitentry * entry, * next; |