+ if (d1->hdr->ph_sec < d2->hdr->ph_sec)
+ return -1;
+ if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
+ d1->hdr->ph_usec < d2->hdr->ph_usec)
+ return -1;
+ if (d1->hdr->ph_sec == d2->hdr->ph_sec &&
+ d1->hdr->ph_usec == d2->hdr->ph_usec)
+ return 0;
+ return 1;
+}
+
+static void print_rec(struct dbg_line ***linevp, int used, int fdout)
+{
+ struct dbg_line **linev = *linevp;
+ int i;
+
+ qsort(linev, used, sizeof(struct dbg_line *), cmp_rec);
+ for (i = 0; i < used; i++) {
+ struct dbg_line *line = linev[i];
+ struct ptldebug_header *hdr = line->hdr;
+ char out[4097];
+ char *buf = out;
+ int bytes;
+ ssize_t bytes_written;
+
+ bytes = sprintf(out, "%08x:%08x:%u.%u%s:%u.%06llu:%u:%u:%u:(%s:%u:%s()) %s",
+ hdr->ph_subsys, hdr->ph_mask,
+ hdr->ph_cpu_id, hdr->ph_type,
+ hdr->ph_flags & PH_FLAG_FIRST_RECORD ? "F" : "",
+ hdr->ph_sec, (unsigned long long)hdr->ph_usec,
+ hdr->ph_stack, hdr->ph_pid, hdr->ph_extern_pid,
+ line->file, hdr->ph_line_num, line->fn, line->text);
+ while (bytes > 0) {
+ bytes_written = write(fdout, buf, bytes);
+ if (bytes_written <= 0)
+ break;
+ bytes -= bytes_written;
+ buf += bytes_written;
+ }
+ free(line->hdr);
+ free(line);
+ }
+ free(linev);
+ *linevp = NULL;
+}
+
+static int add_rec(struct dbg_line *line, struct dbg_line ***linevp, int *lenp,
+ int used)
+{
+ struct dbg_line **linev = *linevp;
+
+ if (used == *lenp) {
+ int nlen = *lenp + 4096;
+ int nsize = nlen * sizeof(struct dbg_line *);
+
+ linev = realloc(*linevp, nsize);
+ if (!linev)
+ return -ENOMEM;
+
+ *linevp = linev;
+ *lenp = nlen;
+ }
+ linev[used] = line;
+
+ return 0;
+}
+
+static void dump_hdr(unsigned long long offset, struct ptldebug_header *hdr)
+{
+ fprintf(stderr, "badly-formed record at offset = %llu\n", offset);
+ fprintf(stderr, " len = %u\n", hdr->ph_len);
+ fprintf(stderr, " flags = %x\n", hdr->ph_flags);
+ fprintf(stderr, " subsystem = %x\n", hdr->ph_subsys);
+ fprintf(stderr, " mask = %x\n", hdr->ph_mask);
+ fprintf(stderr, " cpu_id = %u\n", hdr->ph_cpu_id);
+ fprintf(stderr, " type = %u\n", hdr->ph_type);
+ fprintf(stderr, " seconds = %u\n", hdr->ph_sec);
+ fprintf(stderr, " microseconds = %lu\n", (long)hdr->ph_usec);
+ fprintf(stderr, " stack = %u\n", hdr->ph_stack);
+ fprintf(stderr, " pid = %u\n", hdr->ph_pid);
+ fprintf(stderr, " host pid = %u\n", hdr->ph_extern_pid);
+ fprintf(stderr, " line number = %u\n", hdr->ph_line_num);
+}
+
+#define HDR_SIZE sizeof(*hdr)
+
+static int parse_buffer(int fdin, int fdout)
+{
+ struct dbg_line *line;
+ struct ptldebug_header *hdr;
+ char buf[4097], *ptr;
+ unsigned long dropped = 0, kept = 0, bad = 0;
+ struct dbg_line **linev = NULL;
+ int linev_len = 0;
+ int rc;
+
+ hdr = (void *)buf;
+
+ while (1) {
+ int first_bad = 1;
+ int count;
+
+ count = HDR_SIZE;
+ ptr = buf;
+ readhdr:
+ rc = read(fdin, ptr, count);
+ if (rc <= 0)
+ goto print;
+
+ ptr += rc;
+ count -= rc;
+ if (count > 0)
+ goto readhdr;
+
+ if (hdr->ph_len > 4094 || /* is this header bogus? */
+ hdr->ph_type >= libcfs_tcd_type_max() ||
+ hdr->ph_stack > 65536 ||
+ hdr->ph_sec < (1 << 30) ||
+ hdr->ph_usec > 1000000000 ||
+ hdr->ph_line_num > 65536) {
+ if (first_bad)
+ dump_hdr(lseek(fdin, 0, SEEK_CUR), hdr);
+ bad += first_bad;
+ first_bad = 0;
+
+ /* try to restart on next line */
+ while (count < HDR_SIZE && buf[count] != '\n')
+ count++;
+ if (buf[count] == '\n')
+ count++; /* move past '\n' */
+ if (HDR_SIZE - count > 0) {
+ int left = HDR_SIZE - count;
+
+ memmove(buf, buf + count, left);
+ ptr = buf + left;
+
+ goto readhdr;
+ }
+
+ continue;
+ }
+
+ if (hdr->ph_len == 0)
+ continue;
+
+ count = hdr->ph_len - HDR_SIZE;
+ readmore:
+ rc = read(fdin, ptr, count);
+ if (rc <= 0)