parse_dump.c

Go to the documentation of this file.
00001 
00017 #include "opjitconv.h"
00018 #include "jitdump.h"
00019 #include "opd_printf.h"
00020 #include "op_libiberty.h"
00021 
00022 #include <string.h>
00023 #include <stdio.h>
00024 
00025 /* parse a code load record and add the entry to the jitentry list */
00026 static int parse_code_load(void const * ptr_arg, int size,
00027                unsigned long long end_time)
00028 {
00029     struct jitentry * entry;
00030     int rc = OP_JIT_CONV_OK;
00031     char const * ptr = ptr_arg;
00032     struct jr_code_load const * rec = ptr_arg;
00033     char const * end;
00034     size_t padding_count, rec_totalsize;
00035     end = rec->code_addr ? ptr + size : NULL;
00036 
00037     entry = xcalloc(1, sizeof(struct jitentry));
00038 
00039     // jitentry constructor
00040     entry->next = NULL;
00041     ptr += sizeof(*rec);
00042     /* symbol_name can be malloced so we cast away the constness. */
00043     entry->symbol_name = (char *)ptr;
00044     entry->sym_name_malloced = 0;
00045     ptr += strlen(ptr) + 1;
00046     entry->code = rec->code_addr ? ptr : NULL;
00047     entry->vma = rec->vma;
00048     entry->code_size = rec->code_size;
00049     entry->section = NULL;
00050     entry->life_start = rec->timestamp;
00051     // if nothing else is known the symbol lives till the end of the
00052     // sampling run, this value may be overwritten by an unload record1
00053     // later
00054     entry->life_end = end_time;
00055 
00056     // build list
00057     entry->next = jitentry_list;
00058     jitentry_list = entry;
00059 
00060     /* padding bytes are calculated over the complete record
00061      * (i.e. header + symbol name + code)
00062      */
00063     rec_totalsize = sizeof(*rec) + strlen(entry->symbol_name) + 1 + entry->code_size;
00064     padding_count = PADDING_8ALIGNED(rec_totalsize);
00065 
00066     verbprintf(debug, "record0: name=%s, vma=%llx, code_size=%i, "
00067            "padding_count=%llu, life_start=%lli, life_end=%lli\n", entry->symbol_name,
00068            entry->vma, entry->code_size, (unsigned long long)padding_count, entry->life_start,
00069            entry->life_end);
00070     /* If end == NULL, the dump does not include code, and this sanity
00071      * check is skipped.
00072      */
00073     if (end && (ptr + entry->code_size + padding_count != end)) {
00074         verbprintf(debug, "record total size mismatch\n");
00075         rc = OP_JIT_CONV_FAIL;
00076     }
00077     return rc;
00078 }
00079 
00080 
00081 /*
00082  * parse a code unload record. Search for existing record with this code
00083  * address and fill life_end field with the timestamp. linear search not very
00084  * efficient. FIXME: inefficient
00085  */
00086 static void parse_code_unload(void const * ptr, unsigned long long end_time)
00087 {
00088     struct jr_code_unload const * rec = ptr;
00089     struct jitentry * entry;
00090 
00091     verbprintf(debug,"record1: vma=%llx, life_end=%lli\n",
00092            rec->vma, rec->timestamp);
00099     if (rec->timestamp > 0 && rec->vma != 0) {
00100         for (entry = jitentry_list; entry; entry = entry->next) {
00101             if (entry->vma == rec->vma &&
00102                 entry->life_end == end_time) {
00103                 entry->life_end = rec->timestamp;
00104                 verbprintf(debug,"matching record found\n");
00105                 break;
00106             }
00107         }
00108     }
00109 }
00110 
00111 
00112 /*
00113  * There is no real parsing here, we just record a pointer to the data,
00114  * we will interpret on the fly the record when building the bfd file.
00115  */
00116 static void parse_code_debug_info(void const * ptr, void const * end,
00117                   unsigned long long end_time)
00118 {
00119     struct jr_code_debug_info const * rec = ptr;
00120     struct jitentry_debug_line * debug_line =
00121         xmalloc(sizeof(struct jitentry_debug_line));
00122 
00123     debug_line->data = rec;
00124     debug_line->end = end;
00125     debug_line->life_start = rec->timestamp;
00126     debug_line->life_end = end_time;
00127 
00128     debug_line->next = jitentry_debug_line_list;
00129     jitentry_debug_line_list = debug_line;
00130 }
00131 
00132 
00133 /* parse all entries in the jit dump file and build jitentry_list.
00134  * the code needs to check always whether there is enough
00135  * to read remaining. this is because the file may be written to
00136  * concurrently. */
00137 static int parse_entries(void const * ptr, void const * end,
00138              unsigned long long end_time)
00139 {
00140     int rc = OP_JIT_CONV_OK;
00141     struct jr_prefix const * rec = ptr;
00142 
00143     while ((void *)rec + sizeof(struct jr_prefix) < end) {
00144         if (((void *) rec + rec->total_size) > end) {
00145             verbprintf(debug, "record past end of file\n");
00146             rc = OP_JIT_CONV_FAIL;
00147             break;
00148         }
00149 
00150         switch (rec->id) {
00151         case JIT_CODE_LOAD:
00152             if (parse_code_load(rec, rec->total_size, end_time)) {
00153                 rc = OP_JIT_CONV_FAIL;
00154                 break;
00155             }
00156             break;
00157 
00158         case JIT_CODE_UNLOAD:
00159             parse_code_unload(rec, end_time);
00160             break;
00161 
00162         // end of VM live time, no action
00163         case JIT_CODE_CLOSE:
00164             break;
00165 
00166         case JIT_CODE_DEBUG_INFO:
00167             if (rec->total_size == 0) {
00168                 /* op_write_debug_line_info() ensures to write records with
00169                  * totalsize > 0.
00170                  */
00171                 rc = OP_JIT_CONV_FAIL;
00172                 break;
00173             }
00174 
00175             parse_code_debug_info(rec, end, end_time);
00176             break;
00177 
00178         default:
00179             verbprintf(debug, "unknown record type\n");
00180             rc = OP_JIT_CONV_FAIL;
00181             break;
00182         }
00183 
00184         /* advance to next record (incl. possible padding bytes) */
00185         rec = (void *)rec + rec->total_size;
00186     }
00187 
00188     return rc;
00189 }
00190 
00191 
00192 /* parse the jit dump header information 
00193  * The ptr arg is the address of the pointer to the mmapped
00194  * file, which we modify below.
00195  */
00196 static int parse_header(char const ** ptr, char const * end)
00197 {
00198     int rc = OP_JIT_CONV_OK;
00199     struct jitheader const * header;
00200 
00201     if (*ptr + sizeof(struct jitheader) >= end) {
00202         verbprintf(debug,
00203                "opjitconv: EOF in jitdump file, no header\n");
00204         rc = OP_JIT_CONV_FAIL;
00205         goto out;
00206     }
00207     header = (struct jitheader *)*ptr;
00208     if (header->magic != JITHEADER_MAGIC) {
00209         verbprintf(debug, "opjitconv: Wrong jitdump file magic\n");
00210         rc = OP_JIT_CONV_FAIL;
00211         goto out;
00212     }
00213     if (header->version != JITHEADER_VERSION) {
00214         verbprintf(debug, "opjitconv: Wrong jitdump file version\n");
00215         rc = OP_JIT_CONV_FAIL;
00216         goto out;
00217     }
00218     if (*ptr + header->totalsize > end) {
00219         verbprintf(debug, "opjitconv: EOF in jitdump file, not enough "
00220                "data for header\n");
00221         rc = OP_JIT_CONV_FAIL;
00222         goto out;
00223     }
00224     dump_bfd_arch = header->bfd_arch;
00225     dump_bfd_mach = header->bfd_mach;
00226     dump_bfd_target_name = header->bfd_target;
00227     verbprintf(debug, "header: bfd-arch=%i, bfd-mach=%i,"
00228            " bfd_target_name=%s\n", dump_bfd_arch, dump_bfd_mach,
00229            dump_bfd_target_name);
00230     *ptr = *ptr + header->totalsize;
00231 out:
00232     return rc;
00233 }
00234 
00235 
00236 /* Read in the memory mapped jitdump file.
00237  * Build up jitentry structure and set global variables.
00238 */
00239 int parse_all(void const * start, void const * end,
00240           unsigned long long end_time)
00241 {
00242     char const * ptr = start;
00243     if (!parse_header(&ptr, end))
00244         return parse_entries(ptr, end, end_time);
00245     else
00246         return OP_JIT_CONV_FAIL;
00247 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1