Merge branch 'devicetree/next' of git://git.secretlab.ca/git/linux-2.6
[cascardo/linux.git] / tools / perf / util / header.c
index f2ceb0f..76c0b2c 100644 (file)
@@ -1289,7 +1289,7 @@ int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
        if (access(linkname, F_OK))
                goto out_free;
 
-       if (readlink(linkname, filename, size) < 0)
+       if (readlink(linkname, filename, size - 1) < 0)
                goto out_free;
 
        if (unlink(linkname))
@@ -1703,21 +1703,41 @@ int perf_file_header__read(struct perf_file_header *header,
                        bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
                else
                        return -1;
+       } else if (ph->needs_swap) {
+               unsigned int i;
+               /*
+                * feature bitmap is declared as an array of unsigned longs --
+                * not good since its size can differ between the host that
+                * generated the data file and the host analyzing the file.
+                *
+                * We need to handle endianness, but we don't know the size of
+                * the unsigned long where the file was generated. Take a best
+                * guess at determining it: try 64-bit swap first (ie., file
+                * created on a 64-bit host), and check if the hostname feature
+                * bit is set (this feature bit is forced on as of fbe96f2).
+                * If the bit is not, undo the 64-bit swap and try a 32-bit
+                * swap. If the hostname bit is still not set (e.g., older data
+                * file), punt and fallback to the original behavior --
+                * clearing all feature bits and setting buildid.
+                */
+               for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i)
+                       header->adds_features[i] = bswap_64(header->adds_features[i]);
+
+               if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
+                       for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) {
+                               header->adds_features[i] = bswap_64(header->adds_features[i]);
+                               header->adds_features[i] = bswap_32(header->adds_features[i]);
+                       }
+               }
+
+               if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
+                       bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
+                       set_bit(HEADER_BUILD_ID, header->adds_features);
+               }
        }
 
        memcpy(&ph->adds_features, &header->adds_features,
               sizeof(ph->adds_features));
-       /*
-        * FIXME: hack that assumes that if we need swap the perf.data file
-        * may be coming from an arch with a different word-size, ergo different
-        * DEFINE_BITMAP format, investigate more later, but for now its mostly
-        * safe to assume that we have a build-id section. Trace files probably
-        * have several other issues in this realm anyway...
-        */
-       if (ph->needs_swap) {
-               memset(&ph->adds_features, 0, sizeof(ph->adds_features));
-               perf_header__set_feat(ph, HEADER_BUILD_ID);
-       }
 
        ph->event_offset = header->event_types.offset;
        ph->event_size   = header->event_types.size;
@@ -1895,6 +1915,21 @@ static int perf_file_section__process(struct perf_file_section *section,
                if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
                        pr_debug("Failed to read buildids, continuing...\n");
                break;
+
+       case HEADER_HOSTNAME:
+       case HEADER_OSRELEASE:
+       case HEADER_VERSION:
+       case HEADER_ARCH:
+       case HEADER_NRCPUS:
+       case HEADER_CPUDESC:
+       case HEADER_CPUID:
+       case HEADER_TOTAL_MEM:
+       case HEADER_CMDLINE:
+       case HEADER_EVENT_DESC:
+       case HEADER_CPU_TOPOLOGY:
+       case HEADER_NUMA_TOPOLOGY:
+               break;
+
        default:
                pr_debug("unknown feature %d, continuing...\n", feat);
        }
@@ -2183,15 +2218,29 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
                                   struct perf_session *session __unused)
 {
        union perf_event ev;
+       struct tracing_data *tdata;
        ssize_t size = 0, aligned_size = 0, padding;
        int err __used = 0;
 
+       /*
+        * We are going to store the size of the data followed
+        * by the data contents. Since the fd descriptor is a pipe,
+        * we cannot seek back to store the size of the data once
+        * we know it. Instead we:
+        *
+        * - write the tracing data to the temp file
+        * - get/write the data size to pipe
+        * - write the tracing data from the temp file
+        *   to the pipe
+        */
+       tdata = tracing_data_get(&evlist->entries, fd, true);
+       if (!tdata)
+               return -1;
+
        memset(&ev, 0, sizeof(ev));
 
        ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
-       size = read_tracing_data_size(fd, &evlist->entries);
-       if (size <= 0)
-               return size;
+       size = tdata->size;
        aligned_size = ALIGN(size, sizeof(u64));
        padding = aligned_size - size;
        ev.tracing_data.header.size = sizeof(ev.tracing_data);
@@ -2199,7 +2248,12 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist,
 
        process(&ev, NULL, session);
 
-       err = read_tracing_data(fd, &evlist->entries);
+       /*
+        * The put function will copy all the tracing data
+        * stored in temp file to the pipe.
+        */
+       tracing_data_put(tdata);
+
        write_padded(fd, NULL, 0, padding);
 
        return aligned_size;