scripts/bpftrace: use SO names in bpftrace scripts
If an USDT probe is defined within a shared object, bpftrace expects the path to that shared object instead of an executable. This means that we need to replace __EXE__ in the bpftrace scripts differently, depending on whether the application was linked statically or dynamically. This is now done by the `scripts/bpf/gen.py` script. It lists all available probes, along with their locations, of a process. Then, it matches them to those described in a bpftrace script replacing the __EXE__ markers with the listed location (either a path to the executable or a shared library). If a bpftrace script uses a probe that isn't listed, its __EXE__ will be replaced by a path to the executable. Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Change-Id: I7c323d5f7d948ea57cf8d4d3132e4d59a2de594f Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9807 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
9072c4ad0d
commit
143aa5cb1f
53
scripts/bpf/gen.py
Executable file
53
scripts/bpf/gen.py
Executable file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from argparse import ArgumentParser
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class TraceProcess:
|
||||
def __init__(self, pid):
|
||||
self._path = os.readlink(f'/proc/{pid}/exe')
|
||||
self._pid = pid
|
||||
self._probes = self._init_probes()
|
||||
|
||||
def _init_probes(self):
|
||||
lines = subprocess.check_output(['bpftrace', '-l', '-p', str(self._pid)], text=True)
|
||||
probes = {}
|
||||
for line in lines.split('\n'):
|
||||
parts = line.split(':')
|
||||
if len(parts) < 3:
|
||||
continue
|
||||
ptype, path, function = parts[0], parts[1], parts[-1]
|
||||
probes[(ptype, function)] = path
|
||||
return probes
|
||||
|
||||
def fixup(self, script):
|
||||
pregs = [re.compile(r'({}):__EXE__:(\w+)'.format(ptype)) for ptype in ['usdt', 'uprobe']]
|
||||
with open(script, 'r') as file:
|
||||
lines = file.readlines()
|
||||
result = ''
|
||||
for line in lines:
|
||||
for regex in pregs:
|
||||
match = regex.match(line)
|
||||
if match is not None:
|
||||
ptype, function = match.groups()
|
||||
path = self._probes.get((ptype, function), self._path)
|
||||
line = line.replace('__EXE__', path)
|
||||
break
|
||||
result += line.replace('__EXE__', self._path).replace('__PID__', str(self._pid))
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='bpftrace script generator replacing special ' +
|
||||
'variables in the scripts with appropriate values')
|
||||
parser.add_argument('-p', '--pid', type=int, required=True, help='PID of a traced process')
|
||||
parser.add_argument('scripts', metavar='SCRIPTS', type=str, nargs='+',
|
||||
help='bpftrace scripts to process')
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
proc = TraceProcess(args.pid)
|
||||
for script in args.scripts:
|
||||
print(proc.fixup(script))
|
@ -10,7 +10,7 @@ if [ $# -lt 2 ]; then
|
||||
fi
|
||||
SCRIPTS_DIR=$(readlink -f $(dirname $0))
|
||||
BIN_PATH=$(readlink -f /proc/$1/exe)
|
||||
BPF_SCRIPT=$(sed "s#__EXE__#${BIN_PATH}#g" "${@:2}" | sed "s#__PID__#${1}#g")
|
||||
BPF_SCRIPT=$($SCRIPTS_DIR/bpf/gen.py -p $1 "${@:2}")
|
||||
BPF_SCRIPT+=$($SCRIPTS_DIR/bpf/gen_enums.sh)
|
||||
if [ -n "$ECHO_SCRIPT" ]; then
|
||||
echo "$BPF_SCRIPT"
|
||||
|
Loading…
Reference in New Issue
Block a user