perf tools: Generalize perf_header__adds_read()
[safe/jmp/linux-2.6] / tools / perf / util / header.c
index ca0d657..d8416f0 100644 (file)
@@ -128,26 +128,11 @@ static const char *__perf_magic = "PERFFILE";
 
 #define PERF_MAGIC     (*(u64 *)__perf_magic)
 
-struct perf_file_section {
-       u64 offset;
-       u64 size;
-};
-
 struct perf_file_attr {
        struct perf_event_attr  attr;
        struct perf_file_section        ids;
 };
 
-struct perf_file_header {
-       u64                             magic;
-       u64                             size;
-       u64                             attr_size;
-       struct perf_file_section        attrs;
-       struct perf_file_section        data;
-       struct perf_file_section        event_types;
-       DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
-};
-
 void perf_header__set_feat(struct perf_header *self, int feat)
 {
        set_bit(feat, self->adds_features);
@@ -324,21 +309,23 @@ static void do_read(int fd, void *buf, size_t size)
        }
 }
 
-static void perf_header__adds_read(struct perf_header *self, int fd)
+int perf_header__process_sections(struct perf_header *self, int fd,
+                                 int (*process)(struct perf_file_section *self,
+                                                int feat, int fd))
 {
        struct perf_file_section *feat_sec;
        int nr_sections;
        int sec_size;
        int idx = 0;
-
+       int err = 0, feat = 1;
 
        nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
        if (!nr_sections)
-               return;
+               return 0;
 
        feat_sec = calloc(sizeof(*feat_sec), nr_sections);
        if (!feat_sec)
-               die("No memory");
+               return -1;
 
        sec_size = sizeof(*feat_sec) * nr_sections;
 
@@ -346,25 +333,73 @@ static void perf_header__adds_read(struct perf_header *self, int fd)
 
        do_read(fd, feat_sec, sec_size);
 
-       if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
-               struct perf_file_section *trace_sec;
+       while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
+               if (perf_header__has_feat(self, feat)) {
+                       struct perf_file_section *sec = &feat_sec[idx++];
 
-               trace_sec = &feat_sec[idx++];
-               lseek(fd, trace_sec->offset, SEEK_SET);
-               trace_report(fd);
+                       err = process(sec, feat, fd);
+                       if (err < 0)
+                               break;
+               }
+               ++feat;
        }
 
-       if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
-               struct perf_file_section *buildid_sec;
+       free(feat_sec);
+       return err;
+};
 
-               buildid_sec = &feat_sec[idx++];
-               lseek(fd, buildid_sec->offset, SEEK_SET);
-               if (perf_header__read_build_ids(fd, buildid_sec->offset, buildid_sec->size))
-                       pr_debug("failed to read buildids, continuing...\n");
+int perf_file_header__read(struct perf_file_header *self,
+                          struct perf_header *ph, int fd)
+{
+       lseek(fd, 0, SEEK_SET);
+       do_read(fd, self, sizeof(*self));
+
+       if (self->magic     != PERF_MAGIC ||
+           self->attr_size != sizeof(struct perf_file_attr))
+               return -1;
+
+       if (self->size != sizeof(*self)) {
+               /* Support the previous format */
+               if (self->size == offsetof(typeof(*self), adds_features))
+                       bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
+               else
+                       return -1;
        }
 
-       free(feat_sec);
-};
+       memcpy(&ph->adds_features, &self->adds_features,
+              sizeof(self->adds_features));
+
+       ph->event_offset = self->event_types.offset;
+       ph->event_size   = self->event_types.size;
+       ph->data_offset  = self->data.offset;
+       ph->data_size    = self->data.size;
+       return 0;
+}
+
+static int perf_file_section__process(struct perf_file_section *self,
+                                     int feat, int fd)
+{
+       if (lseek(fd, self->offset, SEEK_SET) < 0) {
+               pr_debug("Failed to lseek to %Ld offset for feature %d, "
+                        "continuing...\n", self->offset, feat);
+               return 0;
+       }
+
+       switch (feat) {
+       case HEADER_TRACE_INFO:
+               trace_report(fd);
+               break;
+
+       case HEADER_BUILD_ID:
+               if (perf_header__read_build_ids(fd, self->offset, self->size))
+                       pr_debug("Failed to read buildids, continuing...\n");
+               break;
+       default:
+               pr_debug("unknown feature %d, continuing...\n", feat);
+       }
+
+       return 0;
+}
 
 struct perf_header *perf_header__read(int fd)
 {
@@ -372,23 +407,11 @@ struct perf_header *perf_header__read(int fd)
        struct perf_file_header f_header;
        struct perf_file_attr   f_attr;
        u64                     f_id;
-
        int nr_attrs, nr_ids, i, j;
 
-       lseek(fd, 0, SEEK_SET);
-       do_read(fd, &f_header, sizeof(f_header));
-
-       if (f_header.magic      != PERF_MAGIC           ||
-           f_header.attr_size  != sizeof(f_attr))
+       if (perf_file_header__read(&f_header, self, fd) < 0)
                die("incompatible file format");
 
-       if (f_header.size != sizeof(f_header)) {
-               /* Support the previous format */
-               if (f_header.size == offsetof(typeof(f_header), adds_features))
-                       bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
-               else
-                       die("incompatible file format");
-       }
        nr_attrs = f_header.attrs.size / sizeof(f_attr);
        lseek(fd, f_header.attrs.offset, SEEK_SET);
 
@@ -422,15 +445,7 @@ struct perf_header *perf_header__read(int fd)
                event_count =  f_header.event_types.size / sizeof(struct perf_trace_event_type);
        }
 
-       memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features));
-
-       self->event_offset = f_header.event_types.offset;
-       self->event_size   = f_header.event_types.size;
-
-       self->data_offset = f_header.data.offset;
-       self->data_size   = f_header.data.size;
-
-       perf_header__adds_read(self, fd);
+       perf_header__process_sections(self, fd, perf_file_section__process);
 
        lseek(fd, self->data_offset, SEEK_SET);