Blob Blame History Raw

ptdump could fail with the following error message:

    ptdump: invalid size request: 0 type: "read page for write"

This is because there is lack of consideration in function
write_buffer_wrapped() that there is possibility that current write
position in the corresponding ring buffer could be just on
page-aligned offset. Then, read size for the 3rd write operation
becomes 0 bytes and then readmem() accepting the 0 bytes in the 4th
argument results in the error with the above error message.

More concretely, function write_buffer_wrapped() retrieves and writes
data on the corresponding ring buffer in 3 write operations as the
following picture:

           current write position
      (2)           (3)  | (1)
     <-----------> <---> v <----------->
    +-------------+---------+----------+
    |             |         |          |
    |             |    P    |          |
    |             |         |          |
    +-------------+---------+----------+

The largest square is the corresponding ring buffer containing the
trace data collected by Intel PT. The downward arrow illustrates the
current write position, i.e. the offset of the write operation() at
the timing when system panic occurs and crash dump is collected. The
small square containing the letter 'P' is the page where the current
write position belongs to. ptdump retrieves and writes the data in
this ring buffer in the order of (1), (2) and (3), i.e. from old to
new data.

Then, note that when the current write position is on the page-aligned
offset, there is no square containing 'P' as:

          current write position
      (2)          | (1)
     <------------>v<----------->
    +-------------++------------+
    |             ||            |
    |             ||            |
    |             ||            |
    +-------------++------------+

and then the write size for the write operation (3) becomes 0 bytes,
meaning that the write operation (3) is unnecessary in this case.



--- ptdump-1.0.3/ptdump.c.orig
+++ ptdump-1.0.3/ptdump.c
@@ -72,7 +72,7 @@ get_member(ulong addr, char *name, char
 	size = MEMBER_SIZE(name, member);
 
 
-	if (!readmem(addr + offset, KVADDR, buf, size, name, FAULT_ON_ERROR))
+	if (!readmem(addr + offset, KVADDR, buf, size, name, RETURN_ON_ERROR))
 		return FALSE;
 
 	return TRUE;
@@ -162,7 +162,7 @@ int init_pt_info(int cpu)
 		ulong page;
 
 		if (!readmem(pgaddr, KVADDR, &page, sizeof(ulong),
-			     "struct page", FAULT_ON_ERROR))
+			     "struct page", RETURN_ON_ERROR))
 			continue;
 
 		pt_info_ptr->buffer_ptr[i] = page;
@@ -194,7 +194,7 @@ int init_pt_info(int cpu)
 	/* Read topa entry */
 	if (!readmem((topa_base) + topa_idx*(sizeof(struct topa_entry)),
 		     KVADDR, &topa, sizeof(topa),
-		     "struct topa_entry", FAULT_ON_ERROR)) {
+		     "struct topa_entry", RETURN_ON_ERROR)) {
 		fprintf(fp, "Cannot read topa table\n");
 		goto out_error;
 	}
@@ -230,7 +230,8 @@ int init_pt_info(int cpu)
 out_error:
 	if (pt_info_ptr->buffer_ptr != NULL)
 		free(pt_info_ptr->buffer_ptr);
-		return FALSE;
+
+	return FALSE;
 }
 
 static inline int is_zero_page(ulong page, int offset)
@@ -247,8 +248,11 @@ static inline int is_zero_page(ulong pag
 
 	memset(buf, 0, PAGESIZE());
 	dbgprintf(fp, "zero page chk: 0x%016lx, %lu\n", read_addr, read_size);
-	readmem(read_addr, KVADDR, buf, read_size, "zero page check",
-	        FAULT_ON_ERROR);
+	if (!readmem(read_addr, KVADDR, buf, read_size, "zero page check",
+		     RETURN_ON_ERROR)) {
+		free(buf);
+		return FALSE;
+	}
 
 	for (i = 0; i < PAGESIZE() - offset; i++) {
 		if (buf[i]) {
@@ -312,8 +316,11 @@ int write_buffer_wrapped(int cpu, FILE *
 		page = pt_info_ptr->buffer_ptr[idx];
 		len = PAGESIZE() - offset;
 
-		readmem(page + offset, KVADDR, buf, len, "read page for write",
-			FAULT_ON_ERROR);
+		if (!readmem(page + offset, KVADDR, buf, len, "read page for write",
+			     RETURN_ON_ERROR)) {
+			free(buf);
+			return FALSE;
+		}
 
 		dbgprintf(fp, "[%d] R/W1 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
 			cpu, page + offset, idx, offset, len);
@@ -332,8 +339,11 @@ int write_buffer_wrapped(int cpu, FILE *
 		page = pt_info_ptr->buffer_ptr[idx];
 		len = PAGESIZE() - offset;
 
-		readmem(page + offset, KVADDR, buf, len, "read page for write",
-			FAULT_ON_ERROR);
+		if (!readmem(page + offset, KVADDR, buf, len, "read page for write",
+			     RETURN_ON_ERROR)) {
+			free(buf);
+			return FALSE;
+		}
 
 		dbgprintf(fp, "[%d] R/W2 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
 			cpu, page + offset, idx, offset, len);
@@ -351,8 +361,14 @@ int write_buffer_wrapped(int cpu, FILE *
 	offset = pt_info_ptr->output_off & mask;
 	len = offset;
 
-	readmem(page, KVADDR, buf, len, "read page for write",
-		FAULT_ON_ERROR);
+	if (!len)
+		goto done;
+
+	if (!readmem(page, KVADDR, buf, len, "read page for write",
+		     RETURN_ON_ERROR)) {
+		free(buf);
+		return FALSE;
+	}
 
 	dbgprintf(fp, "[%d] R/W3 buff: p=0x%lx, i=%d, o=%lu, l=%d\n", cpu,
 		page, idx, offset, len);
@@ -364,6 +380,7 @@ int write_buffer_wrapped(int cpu, FILE *
 		return FALSE;
 	}
 
+done:
 	free(buf);
 	return TRUE;
 }
@@ -388,8 +405,11 @@ int write_buffer_nowrapped(int cpu, FILE
 		page = pt_info_ptr->buffer_ptr[idx];
 		len = PAGESIZE();
 
-		readmem(page, KVADDR, buf, len, "read page for write",
-			FAULT_ON_ERROR);
+		if (!readmem(page, KVADDR, buf, len, "read page for write",
+			     RETURN_ON_ERROR)) {
+			free(buf);
+			return FALSE;
+		}
 
 		dbgprintf(fp, "[%d] R/W1 buff: p=0x%lx, i=%d, o=%lu, l=%d\n",
 			cpu, page, idx, (ulong)0, len);
@@ -406,8 +426,14 @@ int write_buffer_nowrapped(int cpu, FILE
 	page = pt_info_ptr->buffer_ptr[idx];
 	len = pt_info_ptr->output_off & mask;
 
-	readmem(page, KVADDR, buf, len, "read page for write",
-		FAULT_ON_ERROR);
+	if (!len)
+		goto done;
+
+	if (!readmem(page, KVADDR, buf, len, "read page for write",
+		     RETURN_ON_ERROR)) {
+		free(buf);
+		return FALSE;
+	}
 
 	dbgprintf(fp, "[%d] R/W2 buff: p=0x%lx, i=%d, o=%lu, l=%d\n", cpu,
 		page, idx, (ulong)0, len);
@@ -419,6 +445,7 @@ int write_buffer_nowrapped(int cpu, FILE
 		return FALSE;
 	}
 
+done:
 	free(buf);
 	return TRUE;
 }
@@ -491,6 +518,9 @@ cmd_ptdump(void)
 	if (argcnt != 2)
 		cmd_usage(pc->curcmd, SYNOPSIS);
 
+	if (ACTIVE())
+		error(FATAL, "not supported on a live system\n");
+
 	outdir = args[1];
 	if ((ret = mkdir(outdir, mode))) {
 		fprintf(fp, "Cannot create directory %s: %d\n", outdir, ret);
@@ -502,12 +532,12 @@ cmd_ptdump(void)
 		return;
 	}
 
-	/* 
-	 * Set the gdb scope to ensure that the appropriate ring_buffer 
-	 * structure is selected. 
+	/*
+	 * Set the gdb scope to ensure that the appropriate ring_buffer
+	 * structure is selected.
 	 */
 	if (kernel_symbol_exists("perf_mmap_to_page"))
-		gdb_set_crash_scope(symbol_value("perf_mmap_to_page"), 
+		gdb_set_crash_scope(symbol_value("perf_mmap_to_page"),
 			"perf_mmap_to_page");
 
 	online_cpus = get_cpus_online();