Commit 42d6098f authored by Brenden Blanco's avatar Brenden Blanco

tools: switch to v2/3 independent bytes usage

Conform to bytes encoding for some portion of the tools/tests, such that
smoke tests pass on python3. More conversions are surely required.
Signed-off-by: default avatarBrenden Blanco <bblanco@gmail.com>
parent c0ca99a2
...@@ -15,14 +15,14 @@ class TestKSyms(TestCase): ...@@ -15,14 +15,14 @@ class TestKSyms(TestCase):
# Grab the first symbol in kallsyms that has type 't' or 'T'. # Grab the first symbol in kallsyms that has type 't' or 'T'.
# Also, find all aliases of this symbol which are identifiable # Also, find all aliases of this symbol which are identifiable
# by the same address. # by the same address.
with open("/proc/kallsyms") as f: with open("/proc/kallsyms", "rb") as f:
for line in f: for line in f:
# Extract the first 3 columns only. The 4th column # Extract the first 3 columns only. The 4th column
# containing the module name may not exist for all # containing the module name may not exist for all
# symbols. # symbols.
(addr, t, name) = line.strip().split()[:3] (addr, t, name) = line.strip().split()[:3]
if t == "t" or t == "T": if t == b"t" or t == b"T":
if not address: if not address:
address = addr address = addr
if addr == address: if addr == address:
...@@ -32,7 +32,7 @@ class TestKSyms(TestCase): ...@@ -32,7 +32,7 @@ class TestKSyms(TestCase):
return (address, aliases) return (address, aliases)
def test_ksymname(self): def test_ksymname(self):
sym = BPF.ksymname("__kmalloc") sym = BPF.ksymname(b"__kmalloc")
self.assertIsNotNone(sym) self.assertIsNotNone(sym)
self.assertNotEqual(sym, 0) self.assertNotEqual(sym, 0)
...@@ -58,21 +58,23 @@ class Harness(TestCase): ...@@ -58,21 +58,23 @@ class Harness(TestCase):
def tearDown(self): def tearDown(self):
self.process.kill() self.process.kill()
self.process.wait() self.process.wait()
self.process.stdout.close()
self.process = None
def resolve_addr(self): def resolve_addr(self):
sym, offset, module = self.syms.resolve(self.addr, False) sym, offset, module = self.syms.resolve(self.addr, False)
self.assertEqual(sym, self.mangled_name) self.assertEqual(sym, self.mangled_name)
self.assertEqual(offset, 0) self.assertEqual(offset, 0)
self.assertTrue(module[-5:] == 'dummy') self.assertTrue(module[-5:] == b'dummy')
sym, offset, module = self.syms.resolve(self.addr, True) sym, offset, module = self.syms.resolve(self.addr, True)
self.assertEqual(sym, 'some_namespace::some_function(int, int)') self.assertEqual(sym, b'some_namespace::some_function(int, int)')
self.assertEqual(offset, 0) self.assertEqual(offset, 0)
self.assertTrue(module[-5:] == 'dummy') self.assertTrue(module[-5:] == b'dummy')
def resolve_name(self): def resolve_name(self):
script_dir = os.path.dirname(os.path.realpath(__file__)) script_dir = os.path.dirname(os.path.realpath(__file__).encode("utf8"))
addr = self.syms.resolve_name(os.path.join(script_dir, 'dummy'), addr = self.syms.resolve_name(os.path.join(script_dir, b'dummy'),
self.mangled_name) self.mangled_name)
self.assertEqual(addr, self.addr) self.assertEqual(addr, self.addr)
pass pass
...@@ -82,8 +84,8 @@ class TestDebuglink(Harness): ...@@ -82,8 +84,8 @@ class TestDebuglink(Harness):
subprocess.check_output('g++ -o dummy dummy.cc'.split()) subprocess.check_output('g++ -o dummy dummy.cc'.split())
lines = subprocess.check_output('nm dummy'.split()).splitlines() lines = subprocess.check_output('nm dummy'.split()).splitlines()
for line in lines: for line in lines:
if "some_function" in line: if b"some_function" in line:
self.mangled_name = line.split(' ')[2] self.mangled_name = line.split(b' ')[2]
break break
self.assertTrue(self.mangled_name) self.assertTrue(self.mangled_name)
...@@ -108,8 +110,8 @@ class TestBuildid(Harness): ...@@ -108,8 +110,8 @@ class TestBuildid(Harness):
.split()) .split())
lines = subprocess.check_output('nm dummy'.split()).splitlines() lines = subprocess.check_output('nm dummy'.split()).splitlines()
for line in lines: for line in lines:
if "some_function" in line: if b"some_function" in line:
self.mangled_name = line.split(' ')[2] self.mangled_name = line.split(b' ')[2]
break break
self.assertTrue(self.mangled_name) self.assertTrue(self.mangled_name)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Copyright (c) Suchakra Sharma <suchakrapani.sharma@polymtl.ca> # Copyright (c) Suchakra Sharma <suchakrapani.sharma@polymtl.ca>
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
from bcc import BPF, _get_num_open_probes from bcc import BPF, _get_num_open_probes, TRACEFS
import os import os
import sys import sys
from unittest import main, TestCase from unittest import main, TestCase
...@@ -18,9 +18,9 @@ class TestKprobeCnt(TestCase): ...@@ -18,9 +18,9 @@ class TestKprobeCnt(TestCase):
def test_attach1(self): def test_attach1(self):
actual_cnt = 0 actual_cnt = 0
with open("/sys/kernel/debug/tracing/available_filter_functions") as f: with open("%s/available_filter_functions" % TRACEFS, "rb") as f:
for line in f: for line in f:
if str(line).startswith("vfs_"): if line.startswith(b"vfs_"):
actual_cnt += 1 actual_cnt += 1
open_cnt = self.b.num_open_kprobes() open_cnt = self.b.num_open_kprobes()
self.assertEqual(actual_cnt, open_cnt) self.assertEqual(actual_cnt, open_cnt)
......
...@@ -47,7 +47,7 @@ int kprobe__htab_map_lookup_elem(struct pt_regs *ctx, struct bpf_map *map, u64 * ...@@ -47,7 +47,7 @@ int kprobe__htab_map_lookup_elem(struct pt_regs *ctx, struct bpf_map *map, u64 *
stackid = stack_entries[k] stackid = stack_entries[k]
self.assertIsNotNone(stackid) self.assertIsNotNone(stackid)
stack = stack_traces[stackid].ip stack = stack_traces[stackid].ip
self.assertEqual(b.ksym(stack[0]), "htab_map_lookup_elem") self.assertEqual(b.ksym(stack[0]), b"htab_map_lookup_elem")
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -138,16 +138,16 @@ while 1: ...@@ -138,16 +138,16 @@ while 1:
counts = b.get_table("counts") counts = b.get_table("counts")
for k, v in sorted(counts.items(), key=lambda counts: counts[1].value): for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
if re.match('mark_page_accessed', b.ksym(k.ip)) is not None: if re.match(b'mark_page_accessed', b.ksym(k.ip)) is not None:
mpa = max(0, v.value) mpa = max(0, v.value)
if re.match('mark_buffer_dirty', b.ksym(k.ip)) is not None: if re.match(b'mark_buffer_dirty', b.ksym(k.ip)) is not None:
mbd = max(0, v.value) mbd = max(0, v.value)
if re.match('add_to_page_cache_lru', b.ksym(k.ip)) is not None: if re.match(b'add_to_page_cache_lru', b.ksym(k.ip)) is not None:
apcl = max(0, v.value) apcl = max(0, v.value)
if re.match('account_page_dirtied', b.ksym(k.ip)) is not None: if re.match(b'account_page_dirtied', b.ksym(k.ip)) is not None:
apd = max(0, v.value) apd = max(0, v.value)
# access = total cache access incl. reads(mpa) and writes(mbd) # access = total cache access incl. reads(mpa) and writes(mbd)
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
from bcc.utils import ArgString, printb
import bcc.utils as utils
import argparse import argparse
import ctypes as ct import ctypes as ct
import re import re
...@@ -41,8 +43,10 @@ parser.add_argument("-t", "--timestamp", action="store_true", ...@@ -41,8 +43,10 @@ parser.add_argument("-t", "--timestamp", action="store_true",
parser.add_argument("-x", "--fails", action="store_true", parser.add_argument("-x", "--fails", action="store_true",
help="include failed exec()s") help="include failed exec()s")
parser.add_argument("-n", "--name", parser.add_argument("-n", "--name",
type=ArgString,
help="only print commands matching this name (regex), any arg") help="only print commands matching this name (regex), any arg")
parser.add_argument("-l", "--line", parser.add_argument("-l", "--line",
type=ArgString,
help="only print commands where arg contains this line (regex)") help="only print commands where arg contains this line (regex)")
parser.add_argument("--max-args", default="20", parser.add_argument("--max-args", default="20",
help="maximum number of arguments parsed and displayed, defaults to 20") help="maximum number of arguments parsed and displayed, defaults to 20")
...@@ -186,19 +190,19 @@ def print_event(cpu, data, size): ...@@ -186,19 +190,19 @@ def print_event(cpu, data, size):
elif event.type == EventType.EVENT_RET: elif event.type == EventType.EVENT_RET:
if event.retval != 0 and not args.fails: if event.retval != 0 and not args.fails:
skip = True skip = True
if args.name and not re.search(args.name, event.comm): if args.name and not re.search(bytes(args.name), event.comm):
skip = True skip = True
if args.line and not re.search(args.line, if args.line and not re.search(bytes(args.line),
b' '.join(argv[event.pid]).decode()): b' '.join(argv[event.pid])):
skip = True skip = True
if not skip: if not skip:
if args.timestamp: if args.timestamp:
print("%-8.3f" % (time.time() - start_ts), end="") print("%-8.3f" % (time.time() - start_ts), end="")
ppid = get_ppid(event.pid) ppid = get_ppid(event.pid)
print("%-16s %-6s %-6s %3s %s" % (event.comm.decode(), event.pid, ppid = b"%d" % ppid if ppid > 0 else b"?"
ppid if ppid > 0 else "?", event.retval, printb(b"%-16s %-6d %-6s %3d %s" % (event.comm, event.pid,
b' '.join(argv[event.pid]).decode())) ppid, event.retval, b' '.join(argv[event.pid])))
try: try:
del(argv[event.pid]) del(argv[event.pid])
except Exception: except Exception:
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# 18-Oct-2016 Sasha Goldshtein Generalized for uprobes, tracepoints, USDT. # 18-Oct-2016 Sasha Goldshtein Generalized for uprobes, tracepoints, USDT.
from __future__ import print_function from __future__ import print_function
from bcc import BPF, USDT from bcc import ArgString, BPF, USDT
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
import os import os
...@@ -49,15 +49,15 @@ class Probe(object): ...@@ -49,15 +49,15 @@ class Probe(object):
t:cat:event -- probe a kernel tracepoint t:cat:event -- probe a kernel tracepoint
u:lib:probe -- probe a USDT tracepoint u:lib:probe -- probe a USDT tracepoint
""" """
parts = pattern.split(':') parts = bytes(pattern).split(b':')
if len(parts) == 1: if len(parts) == 1:
parts = ["p", "", parts[0]] parts = [b"p", b"", parts[0]]
elif len(parts) == 2: elif len(parts) == 2:
parts = ["p", parts[0], parts[1]] parts = [b"p", parts[0], parts[1]]
elif len(parts) == 3: elif len(parts) == 3:
if parts[0] == "t": if parts[0] == b"t":
parts = ["t", "", "%s:%s" % tuple(parts[1:])] parts = [b"t", b"", b"%s:%s" % tuple(parts[1:])]
if parts[0] not in ["p", "t", "u"]: if parts[0] not in [b"p", b"t", b"u"]:
raise Exception("Type must be 'p', 't', or 'u', but got %s" % raise Exception("Type must be 'p', 't', or 'u', but got %s" %
parts[0]) parts[0])
else: else:
...@@ -66,10 +66,10 @@ class Probe(object): ...@@ -66,10 +66,10 @@ class Probe(object):
(self.type, self.library, self.pattern) = parts (self.type, self.library, self.pattern) = parts
if not use_regex: if not use_regex:
self.pattern = self.pattern.replace('*', '.*') self.pattern = self.pattern.replace(b'*', b'.*')
self.pattern = '^' + self.pattern + '$' self.pattern = b'^' + self.pattern + b'$'
if (self.type == "p" and self.library) or self.type == "u": if (self.type == b"p" and self.library) or self.type == b"u":
libpath = BPF.find_library(self.library) libpath = BPF.find_library(self.library)
if libpath is None: if libpath is None:
# This might be an executable (e.g. 'bash') # This might be an executable (e.g. 'bash')
...@@ -83,46 +83,46 @@ class Probe(object): ...@@ -83,46 +83,46 @@ class Probe(object):
self.trace_functions = {} # map location number to function name self.trace_functions = {} # map location number to function name
def is_kernel_probe(self): def is_kernel_probe(self):
return self.type == "t" or (self.type == "p" and self.library == "") return self.type == b"t" or (self.type == b"p" and self.library == b"")
def attach(self): def attach(self):
if self.type == "p" and not self.library: if self.type == b"p" and not self.library:
for index, function in self.trace_functions.items(): for index, function in self.trace_functions.items():
self.bpf.attach_kprobe( self.bpf.attach_kprobe(
event=function, event=function,
fn_name="trace_count_%d" % index) fn_name="trace_count_%d" % index)
elif self.type == "p" and self.library: elif self.type == b"p" and self.library:
for index, function in self.trace_functions.items(): for index, function in self.trace_functions.items():
self.bpf.attach_uprobe( self.bpf.attach_uprobe(
name=self.library, name=self.library,
sym=function, sym=function,
fn_name="trace_count_%d" % index, fn_name="trace_count_%d" % index,
pid=self.pid or -1) pid=self.pid or -1)
elif self.type == "t": elif self.type == b"t":
for index, function in self.trace_functions.items(): for index, function in self.trace_functions.items():
self.bpf.attach_tracepoint( self.bpf.attach_tracepoint(
tp=function, tp=function,
fn_name="trace_count_%d" % index) fn_name="trace_count_%d" % index)
elif self.type == "u": elif self.type == b"u":
pass # Nothing to do -- attach already happened in `load` pass # Nothing to do -- attach already happened in `load`
def _add_function(self, template, probe_name): def _add_function(self, template, probe_name):
new_func = "trace_count_%d" % self.matched new_func = b"trace_count_%d" % self.matched
text = template.replace("PROBE_FUNCTION", new_func) text = template.replace(b"PROBE_FUNCTION", new_func)
text = text.replace("LOCATION", str(self.matched)) text = text.replace(b"LOCATION", b"%d" % self.matched)
self.trace_functions[self.matched] = probe_name self.trace_functions[self.matched] = probe_name
self.matched += 1 self.matched += 1
return text return text
def _generate_functions(self, template): def _generate_functions(self, template):
self.usdt = None self.usdt = None
text = "" text = b""
if self.type == "p" and not self.library: if self.type == b"p" and not self.library:
functions = BPF.get_kprobe_functions(self.pattern) functions = BPF.get_kprobe_functions(self.pattern)
verify_limit(len(functions)) verify_limit(len(functions))
for function in functions: for function in functions:
text += self._add_function(template, function) text += self._add_function(template, function)
elif self.type == "p" and self.library: elif self.type == b"p" and self.library:
# uprobes are tricky because the same function may have multiple # uprobes are tricky because the same function may have multiple
# addresses, and the same address may be mapped to multiple # addresses, and the same address may be mapped to multiple
# functions. We aren't allowed to create more than one uprobe # functions. We aren't allowed to create more than one uprobe
...@@ -139,12 +139,12 @@ class Probe(object): ...@@ -139,12 +139,12 @@ class Probe(object):
addresses.add(address) addresses.add(address)
functions.add(function) functions.add(function)
text += self._add_function(template, function) text += self._add_function(template, function)
elif self.type == "t": elif self.type == b"t":
tracepoints = BPF.get_tracepoints(self.pattern) tracepoints = BPF.get_tracepoints(self.pattern)
verify_limit(len(tracepoints)) verify_limit(len(tracepoints))
for tracepoint in tracepoints: for tracepoint in tracepoints:
text += self._add_function(template, tracepoint) text += self._add_function(template, tracepoint)
elif self.type == "u": elif self.type == b"u":
self.usdt = USDT(path=self.library, pid=self.pid) self.usdt = USDT(path=self.library, pid=self.pid)
matches = [] matches = []
for probe in self.usdt.enumerate_probes(): for probe in self.usdt.enumerate_probes():
...@@ -154,7 +154,7 @@ class Probe(object): ...@@ -154,7 +154,7 @@ class Probe(object):
matches.append(probe.name) matches.append(probe.name)
verify_limit(len(matches)) verify_limit(len(matches))
for match in matches: for match in matches:
new_func = "trace_count_%d" % self.matched new_func = b"trace_count_%d" % self.matched
text += self._add_function(template, match) text += self._add_function(template, match)
self.usdt.enable_probe(match, new_func) self.usdt.enable_probe(match, new_func)
if debug: if debug:
...@@ -162,7 +162,7 @@ class Probe(object): ...@@ -162,7 +162,7 @@ class Probe(object):
return text return text
def load(self): def load(self):
trace_count_text = """ trace_count_text = b"""
int PROBE_FUNCTION(void *ctx) { int PROBE_FUNCTION(void *ctx) {
FILTER FILTER
int loc = LOCATION; int loc = LOCATION;
...@@ -174,7 +174,7 @@ int PROBE_FUNCTION(void *ctx) { ...@@ -174,7 +174,7 @@ int PROBE_FUNCTION(void *ctx) {
return 0; return 0;
} }
""" """
bpf_text = """#include <uapi/linux/ptrace.h> bpf_text = b"""#include <uapi/linux/ptrace.h>
BPF_ARRAY(counts, u64, NUMLOCATIONS); BPF_ARRAY(counts, u64, NUMLOCATIONS);
""" """
...@@ -182,15 +182,15 @@ BPF_ARRAY(counts, u64, NUMLOCATIONS); ...@@ -182,15 +182,15 @@ BPF_ARRAY(counts, u64, NUMLOCATIONS);
# We really mean the tgid from the kernel's perspective, which is in # We really mean the tgid from the kernel's perspective, which is in
# the top 32 bits of bpf_get_current_pid_tgid(). # the top 32 bits of bpf_get_current_pid_tgid().
if self.pid: if self.pid:
trace_count_text = trace_count_text.replace('FILTER', trace_count_text = trace_count_text.replace(b'FILTER',
"""u32 pid = bpf_get_current_pid_tgid() >> 32; b"""u32 pid = bpf_get_current_pid_tgid() >> 32;
if (pid != %d) { return 0; }""" % self.pid) if (pid != %d) { return 0; }""" % self.pid)
else: else:
trace_count_text = trace_count_text.replace('FILTER', '') trace_count_text = trace_count_text.replace(b'FILTER', b'')
bpf_text += self._generate_functions(trace_count_text) bpf_text += self._generate_functions(trace_count_text)
bpf_text = bpf_text.replace("NUMLOCATIONS", bpf_text = bpf_text.replace(b"NUMLOCATIONS",
str(len(self.trace_functions))) b"%d" % len(self.trace_functions))
if debug: if debug:
print(bpf_text) print(bpf_text)
...@@ -242,6 +242,7 @@ class Tool(object): ...@@ -242,6 +242,7 @@ class Tool(object):
parser.add_argument("-D", "--debug", action="store_true", parser.add_argument("-D", "--debug", action="store_true",
help="print BPF program before starting (for debugging purposes)") help="print BPF program before starting (for debugging purposes)")
parser.add_argument("pattern", parser.add_argument("pattern",
type=ArgString,
help="search expression for events") help="search expression for events")
self.args = parser.parse_args() self.args = parser.parse_args()
global debug global debug
...@@ -260,7 +261,7 @@ class Tool(object): ...@@ -260,7 +261,7 @@ class Tool(object):
self.probe.load() self.probe.load()
self.probe.attach() self.probe.attach()
print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
(self.probe.matched, self.args.pattern)) (self.probe.matched, bytes(self.args.pattern)))
exiting = 0 if self.args.interval else 1 exiting = 0 if self.args.interval else 1
seconds = 0 seconds = 0
while True: while True:
......
...@@ -471,7 +471,7 @@ def print_outstanding(): ...@@ -471,7 +471,7 @@ def print_outstanding():
key=lambda a: a.size)[-top_stacks:] key=lambda a: a.size)[-top_stacks:]
for alloc in to_show: for alloc in to_show:
print("\t%d bytes in %d allocations from stack\n\t\t%s" % print("\t%d bytes in %d allocations from stack\n\t\t%s" %
(alloc.size, alloc.count, "\n\t\t".join(alloc.stack))) (alloc.size, alloc.count, b"\n\t\t".join(alloc.stack)))
def print_outstanding_combined(): def print_outstanding_combined():
stack_traces = bpf["stack_traces"] stack_traces = bpf["stack_traces"]
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
from bcc.utils import printb
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
import signal import signal
...@@ -124,7 +125,7 @@ while 1: ...@@ -124,7 +125,7 @@ while 1:
line = 0 line = 0
for k, v in reversed(sorted(counts.items(), for k, v in reversed(sorted(counts.items(),
key=lambda counts: counts[1].size)): key=lambda counts: counts[1].size)):
print("%-32s %6d %10d" % (k.name.decode(), v.count, v.size)) printb(b"%-32s %6d %10d" % (k.name, v.count, v.size))
line += 1 line += 1
if line >= maxrows: if line >= maxrows:
......
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