Commit 3953c708 authored by Nikita V. Shirokov's avatar Nikita V. Shirokov Committed by yonghong-song

[trace.py]: allow to use STRCMP helper with binary values (#1900)

* [trace.py]: allow to use STRCMP helper with binary values

Summary:
sometimes in probe you want to compare char* w/ some predefined value
which is not a string. e.g. setsockopt syscall has signature like this:
sys_setsockopt(int fd, int level, int optname, char* optval, int optlen)
and if you want to catch where/who is setting up specific value you are
forced to compare optval against some predefined array. it's not
possible today w/ trace.py and in this diff i'm adding such ability

Test Plan:
as example: we want to catch setsockopt when someone is setting up
IP_TOS equal to 108
trace.py 'sys_setsockopt(int fd, int level, int optname, char* optval,
int optlen)(level==0 && optname == 1 && STRCMP("{0x6C,0x00, 0x00,
0x00}", optval))' -U -M 1 --bin_cmp -v

without this new modifier:
static inline bool streq_0(char const *ignored, uintptr_t str) {
        char needle[] = "{0x6C,0x00, 0x00, 0x00}";
        char haystack[sizeof(needle)];
        bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
        for (int i = 0; i < sizeof(needle) - 1; ++i) {
                if (needle[i] != haystack[i]) {
                        return false;
                }
        }
        return true;
}

// see needle is qouted above

with:

tatic inline bool streq_0(char const *ignored, uintptr_t str) {
        char needle[] = {0x6C,0x00, 0x00, 0x00};
        char haystack[sizeof(needle)];
        bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
        for (int i = 0; i < sizeof(needle) - 1; ++i) {
                if (needle[i] != haystack[i]) {
                        return false;
                }
        }
        return true;
}

...
PID     TID     COMM            FUNC             -
1855611 1863183 worker          sys_setsockopt   found

* adding example of --bin_cmp flag usage
parent 230c9c00
...@@ -48,6 +48,9 @@ Print the time column. ...@@ -48,6 +48,9 @@ Print the time column.
\-C \-C
Print CPU id. Print CPU id.
.TP .TP
\-B
Treat argument of STRCMP helper as a binary value
.TP
\-K \-K
Print the kernel stack for each event. Print the kernel stack for each event.
.TP .TP
......
...@@ -48,6 +48,7 @@ class Probe(object): ...@@ -48,6 +48,7 @@ class Probe(object):
cls.tgid = args.tgid or -1 cls.tgid = args.tgid or -1
cls.pid = args.pid or -1 cls.pid = args.pid or -1
cls.page_cnt = args.buffer_pages cls.page_cnt = args.buffer_pages
cls.bin_cmp = args.bin_cmp
def __init__(self, probe, string_size, kernel_stack, user_stack): def __init__(self, probe, string_size, kernel_stack, user_stack):
self.usdt = None self.usdt = None
...@@ -271,7 +272,11 @@ static inline bool %s(char const *ignored, uintptr_t str) { ...@@ -271,7 +272,11 @@ static inline bool %s(char const *ignored, uintptr_t str) {
expr = expr.replace(alias, replacement) expr = expr.replace(alias, replacement)
for alias, replacement in Probe.aliases_common.items(): for alias, replacement in Probe.aliases_common.items():
expr = expr.replace(alias, replacement) expr = expr.replace(alias, replacement)
matches = re.finditer('STRCMP\\(("[^"]+\\")', expr) if self.bin_cmp:
STRCMP_RE = 'STRCMP\\(\"([^"]+)\\"'
else:
STRCMP_RE = 'STRCMP\\(("[^"]+\\")'
matches = re.finditer(STRCMP_RE, expr)
for match in matches: for match in matches:
string = match.group(1) string = match.group(1)
fname = self._generate_streq_function(string) fname = self._generate_streq_function(string)
...@@ -680,6 +685,8 @@ trace -I 'linux/fs_struct.h' 'mntns_install "users = %d", $task->fs->users' ...@@ -680,6 +685,8 @@ trace -I 'linux/fs_struct.h' 'mntns_install "users = %d", $task->fs->users'
help="print time column") help="print time column")
parser.add_argument("-C", "--print_cpu", action="store_true", parser.add_argument("-C", "--print_cpu", action="store_true",
help="print CPU id") help="print CPU id")
parser.add_argument("-B", "--bin_cmp", action="store_true",
help="allow to use STRCMP with binary values")
parser.add_argument("-K", "--kernel-stack", parser.add_argument("-K", "--kernel-stack",
action="store_true", help="output kernel stack trace") action="store_true", help="output kernel stack trace")
parser.add_argument("-U", "--user-stack", parser.add_argument("-U", "--user-stack",
......
...@@ -138,7 +138,7 @@ The "%U" format specifier tells trace to resolve arg3 as a user-space symbol, ...@@ -138,7 +138,7 @@ The "%U" format specifier tells trace to resolve arg3 as a user-space symbol,
if possible. Similarly, use "%K" for kernel symbols. if possible. Similarly, use "%K" for kernel symbols.
Ruby, Node, and OpenJDK are also instrumented with USDT. For example, let's Ruby, Node, and OpenJDK are also instrumented with USDT. For example, let's
trace Ruby methods being called (this requires a version of Ruby built with trace Ruby methods being called (this requires a version of Ruby built with
the --enable-dtrace configure flag): the --enable-dtrace configure flag):
# trace 'u:ruby:method__entry "%s.%s", arg1, arg2' -p $(pidof irb) -T # trace 'u:ruby:method__entry "%s.%s", arg1, arg2' -p $(pidof irb) -T
...@@ -234,6 +234,18 @@ The perf ring buffer size can be changed with -b. The unit is size per-CPU buffe ...@@ -234,6 +234,18 @@ The perf ring buffer size can be changed with -b. The unit is size per-CPU buffe
size and is measured in pages. The value must be a power of two and defaults to size and is measured in pages. The value must be a power of two and defaults to
64 pages. 64 pages.
# trace.py 'sys_setsockopt(int fd, int level, int optname, char* optval, int optlen)(level==0 && optname == 1 && STRCMP("{0x6C, 0x00, 0x00, 0x00}", optval))' -U -M 1 --bin_cmp
PID TID COMM FUNC -
1855611 1863183 worker sys_setsockopt found
In this example we are catching setsockopt syscall to change IPv4 IP_TOS
value only for the cases where new TOS value is equal to 108. we are using
STRCMP helper in binary mode (--bin_cmp flag) to compare optval array
against int value of 108 (parametr of setsockopt call) in hex representation
(little endian format)
USAGE message: USAGE message:
...@@ -261,7 +273,8 @@ optional arguments: ...@@ -261,7 +273,8 @@ optional arguments:
number of events to print before quitting number of events to print before quitting
-t, --timestamp print timestamp column (offset from trace start) -t, --timestamp print timestamp column (offset from trace start)
-T, --time print time column -T, --time print time column
-C, --print_cpu print CPU id -C, --print_cpu print CPU id
-B, --bin_cmp allow to use STRCMP with binary values
-K, --kernel-stack output kernel stack trace -K, --kernel-stack output kernel stack trace
-U, --user-stack output user stack trace -U, --user-stack output user stack trace
-a, --address print virtual address in stacks -a, --address print virtual address in stacks
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment