oprofile 0.9.6
Copy in the rest of the oprofile 0.9.6 tree so we have a source
copy to match the prebuilt binaries that are checked into
external/.
Change-Id: Iaac327571d5d583594a4194973bf256569061048
diff --git a/opjitconv/parse_dump.c b/opjitconv/parse_dump.c
new file mode 100644
index 0000000..2625c7c
--- /dev/null
+++ b/opjitconv/parse_dump.c
@@ -0,0 +1,247 @@
+/**
+ * @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
+ * @Modifications Daniel Hansel
+ *
+ * Copyright IBM Corporation 2007
+ *
+ */
+
+#include "opjitconv.h"
+#include "jitdump.h"
+#include "opd_printf.h"
+#include "op_libiberty.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/* parse a code load record and add the entry to the jitentry list */
+static int parse_code_load(void const * ptr_arg, int size,
+ unsigned long long end_time)
+{
+ struct jitentry * entry;
+ int rc = OP_JIT_CONV_OK;
+ char const * ptr = ptr_arg;
+ struct jr_code_load const * rec = ptr_arg;
+ char const * end;
+ size_t padding_count, rec_totalsize;
+ end = rec->code_addr ? ptr + size : NULL;
+
+ entry = xcalloc(1, sizeof(struct jitentry));
+
+ // jitentry constructor
+ entry->next = NULL;
+ ptr += sizeof(*rec);
+ /* symbol_name can be malloced so we cast away the constness. */
+ entry->symbol_name = (char *)ptr;
+ entry->sym_name_malloced = 0;
+ ptr += strlen(ptr) + 1;
+ entry->code = rec->code_addr ? ptr : NULL;
+ entry->vma = rec->vma;
+ entry->code_size = rec->code_size;
+ entry->section = NULL;
+ entry->life_start = rec->timestamp;
+ // if nothing else is known the symbol lives 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;
+
+ /* padding bytes are calculated over the complete record
+ * (i.e. header + symbol name + code)
+ */
+ rec_totalsize = sizeof(*rec) + strlen(entry->symbol_name) + 1 + entry->code_size;
+ padding_count = PADDING_8ALIGNED(rec_totalsize);
+
+ verbprintf(debug, "record0: name=%s, vma=%llx, code_size=%i, "
+ "padding_count=%llu, life_start=%lli, life_end=%lli\n", entry->symbol_name,
+ entry->vma, entry->code_size, (unsigned long long)padding_count, entry->life_start,
+ entry->life_end);
+ /* If end == NULL, the dump does not include code, and this sanity
+ * check is skipped.
+ */
+ if (end && (ptr + entry->code_size + padding_count != end)) {
+ verbprintf(debug, "record total size mismatch\n");
+ rc = OP_JIT_CONV_FAIL;
+ }
+ return rc;
+}
+
+
+/*
+ * parse a code unload record. Search for existing record with this code
+ * address and fill life_end field with the timestamp. linear search not very
+ * efficient. FIXME: inefficient
+ */
+static void parse_code_unload(void const * ptr, unsigned long long end_time)
+{
+ struct jr_code_unload const * rec = ptr;
+ struct jitentry * entry;
+
+ verbprintf(debug,"record1: vma=%llx, life_end=%lli\n",
+ rec->vma, rec->timestamp);
+ /**
+ * Normally we won't get a jr_code_unload with a zero time stamp or
+ * a zero code address. The code address is directly provided by the JVMTI.
+ * The documentation of JVMTI does not say anything about the address value if
+ * it could be zero or not. Therefore it is only a sanity check at the moment.
+ */
+ if (rec->timestamp > 0 && rec->vma != 0) {
+ for (entry = jitentry_list; entry; entry = entry->next) {
+ if (entry->vma == rec->vma &&
+ entry->life_end == end_time) {
+ entry->life_end = rec->timestamp;
+ verbprintf(debug,"matching record found\n");
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * There is no real parsing here, we just record a pointer to the data,
+ * we will interpret on the fly the record when building the bfd file.
+ */
+static void parse_code_debug_info(void const * ptr, void const * end,
+ unsigned long long end_time)
+{
+ struct jr_code_debug_info const * rec = ptr;
+ struct jitentry_debug_line * debug_line =
+ xmalloc(sizeof(struct jitentry_debug_line));
+
+ debug_line->data = rec;
+ debug_line->end = end;
+ debug_line->life_start = rec->timestamp;
+ debug_line->life_end = end_time;
+
+ debug_line->next = jitentry_debug_line_list;
+ jitentry_debug_line_list = debug_line;
+}
+
+
+/* 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(void const * ptr, void const * end,
+ unsigned long long end_time)
+{
+ int rc = OP_JIT_CONV_OK;
+ struct jr_prefix const * rec = ptr;
+
+ while ((void *)rec + sizeof(struct jr_prefix) < end) {
+ if (((void *) rec + rec->total_size) > end) {
+ verbprintf(debug, "record past end of file\n");
+ rc = OP_JIT_CONV_FAIL;
+ break;
+ }
+
+ switch (rec->id) {
+ case JIT_CODE_LOAD:
+ if (parse_code_load(rec, rec->total_size, end_time)) {
+ rc = OP_JIT_CONV_FAIL;
+ break;
+ }
+ break;
+
+ case JIT_CODE_UNLOAD:
+ parse_code_unload(rec, end_time);
+ break;
+
+ // end of VM live time, no action
+ case JIT_CODE_CLOSE:
+ break;
+
+ case JIT_CODE_DEBUG_INFO:
+ if (rec->total_size == 0) {
+ /* op_write_debug_line_info() ensures to write records with
+ * totalsize > 0.
+ */
+ rc = OP_JIT_CONV_FAIL;
+ break;
+ }
+
+ parse_code_debug_info(rec, end, end_time);
+ break;
+
+ default:
+ verbprintf(debug, "unknown record type\n");
+ rc = OP_JIT_CONV_FAIL;
+ break;
+ }
+
+ /* advance to next record (incl. possible padding bytes) */
+ rec = (void *)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 const ** ptr, char const * end)
+{
+ int rc = OP_JIT_CONV_OK;
+ struct jitheader const * header;
+
+ if (*ptr + sizeof(struct jitheader) >= end) {
+ 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;
+ }
+ if (*ptr + header->totalsize > end) {
+ verbprintf(debug, "opjitconv: EOF in jitdump file, not enough "
+ "data for header\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(void const * start, void const * end,
+ unsigned long long end_time)
+{
+ char const * ptr = start;
+ if (!parse_header(&ptr, end))
+ return parse_entries(ptr, end, end_time);
+ else
+ return OP_JIT_CONV_FAIL;
+}