Signed decimal.
.TP
%m
-Safely reads kernel memory at the given address, outputs its content. The optional precision specifier (not field width) determines the number of bytes to read - default is 1 byte. %10.4m prints 4 bytes of the memory in a 10-character-wide field.
+Safely reads kernel (without #) or user (with #) memory at the given address, outputs its content. The optional precision specifier (not field width) determines the number of bytes to read - default is 1 byte. %10.4m prints 4 bytes of the memory in a 10-character-wide field. Note, on some architectures user memory can still be read without #.
.TP
%M
Same as %m, but outputs in hexadecimal. The minimal size of output is double the optional precision specifier - default is 1 byte (2 hex chars). %10.4M prints 4 bytes of the memory as 8 hexadecimal characters in a 10-character-wide field. %.*M hex-dumps a given number of bytes from a given buffer.
.IR #
flag selects the alternate forms. For octal, this prefixes a 0. For hex, this
prefixes 0x or 0X, depending on case. For characters, this escapes
-non-printing values with either C-like escapes or raw octal.
+non-printing values with either C-like escapes or raw octal. In the case of %#m/%#M,
+this safely accesses user space memory rather than kernel space memory.
.PP
Examples:
.SAMPLE
/* PR13386: Skip if called with null context */
c = _stp_runtime_get_context();
if (c) for (i = 0; i < len && str < end; i++) {
- unsigned char c_tmp = kread((unsigned char *)(ptr));
- ptr++;
+ unsigned char c_tmp;
+ if (flags & STP_SPECIAL)
+ c_tmp = uread((unsigned char *)(ptr));
+ else
+ c_tmp = kread((unsigned char *)(ptr));
+ ptr++;
*str++ = _stp_hex_asc[(c_tmp & 0xf0) >> 4];
*str++ = _stp_hex_asc[(c_tmp & 0x0f)];
}
/* PR13386: Skip if called with null context */
c = _stp_runtime_get_context();
if (c) for (i = 0; i < len && str <= end; ++i) {
- *str++ = kread((unsigned char *)(ptr));
- ptr++;
+ if (flags & STP_SPECIAL)
+ *str++ = uread((unsigned char *)(ptr));
+ else
+ *str++ = kread((unsigned char *)(ptr));
+ ptr++;
}
}
else /* %s format */
--- /dev/null
+#include <unistd.h>
+
+int main()
+{
+ char buffer[7] = "foobar\n";
+ write(1, buffer, 7);
+
+ char buffer2[2] = {'\0','\n'};
+ write(1, buffer2, 2);
+
+ return 0;
+}
--- /dev/null
+# Check that %#M and %#m within printf work correctly.
+
+set test "print_user_buffer"
+set srcfile "$srcdir/$subdir/$test.c"
+set exefile "[pwd]/$test.exe"
+set test_flags "additional_flags=-g"
+set res [target_compile "$srcfile" "$exefile" executable "$test_flags"]
+
+if { $res != ""} {
+ verbose "target_compile failed: $res" 2
+ fail "$test compile"
+ untested "$test"
+ return
+} else {
+ pass "$test compile"
+}
+stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string -c "$exefile > /dev/null"
--- /dev/null
+global errors = 0
+
+probe begin { println("systemtap starting probe") }
+probe end
+{
+ println("systemtap ending probe")
+ if (!errors)
+ println("systemtap test success")
+}
+
+probe syscall.write
+{
+ if (!target_set_pid(pid())) next;
+
+ value = sprintf("%#.*M",$count, $buf)
+ if (value != "666f6f6261720a"&& value!= "000a")
+ errors++
+
+ value = sprintf("%#.*m",$count, $buf)
+ if (value != "foobar\n" && value !="\0\n")
+ errors++
+
+ try {
+ errors++
+ value = sprintf("%#.*M",$count, $fd)
+ }
+ catch {
+ errors--
+ }
+ try {
+ errors++
+ value = sprintf("%#.*m", $count, $fd)
+ }
+ catch {
+ errors--
+ }
+
+}