diff mbox series

[6/8] trace-cruncher: Add tc_eprobe class to ft_utiles

Message ID 20220210152339.363943-7-y.karadz@gmail.com (mailing list archive)
State Accepted
Headers show
Series trace-cruncher:Fixes before v0.2 (Beta) | expand

Commit Message

Yordan Karadzhov Feb. 10, 2022, 3:23 p.m. UTC
Define a Python class and helper methods to be used for easy manipulation
of kernel eprobes.

Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@gmail.com>
---
 examples/eprobe.py                            | 13 ++++-
 tracecruncher/ft_utils.py                     | 56 ++++++++++++++++---
 .../tests/1_unit/test_01_ftracepy_unit.py     | 14 +++++
 3 files changed, 72 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/examples/eprobe.py b/examples/eprobe.py
index 85b0685..a8be907 100755
--- a/examples/eprobe.py
+++ b/examples/eprobe.py
@@ -11,8 +11,10 @@  import sys
 import tracecruncher.ftracepy as ft
 import tracecruncher.ft_utils as tc
 
-open_probe = ft.eprobe(event='sopen_in', target_system='syscalls',
-                       target_event='sys_enter_openat', fetchargs='file=+0($filename):ustring')
+fields = tc.eprobe_add_string_field(name='file', target_field='filename',
+                                    usr_space=True)
+event = tc.tc_event('syscalls', 'sys_enter_openat')
+eprobe = tc.tc_eprobe(name='sopen_in', target_event=event, fields=fields)
 
 tep = tc.local_tep()
 
@@ -25,5 +27,10 @@  if __name__ == "__main__":
         sys.exit(1)
 
     inst = ft.create_instance(tracing_on=False)
-    open_probe.enable(instance=inst)
+
+    # Enable the probe.
+    eprobe.enable(instance=inst)
+
+    # Subscribe for the kprobe event (using the default function name 'callback')
+    # and trace the user process.
     ft.trace_process(instance=inst, argv=sys.argv[1:])
diff --git a/tracecruncher/ft_utils.py b/tracecruncher/ft_utils.py
index 67e020f..b27f38a 100644
--- a/tracecruncher/ft_utils.py
+++ b/tracecruncher/ft_utils.py
@@ -81,22 +81,29 @@  class tc_event:
                               event=self.name)
 
 
-class _kprobe_base(tc_event):
-    def __init__(self, name, func):
+class _dynevent(tc_event):
+    def __init__(self, name):
         """ Constructor.
         """
         super().__init__(system=ft.tc_event_system(), name=name, static=False)
-        self.func = func
-        self.kp = None
+        self.evt = None
         self.evt_id = -1
 
     def register(self):
         """ Register this probe to Ftrace.
         """
-        self.kp.register()
+        self.evt.register()
         self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name)
 
 
+class _kprobe_base(_dynevent):
+    def __init__(self, name, func):
+        """ Constructor.
+        """
+        super().__init__(name=name)
+        self.func = func
+
+
 class tc_kprobe(_kprobe_base):
     def __init__(self, name, func, fields):
         """ Constructor.
@@ -104,7 +111,7 @@  class tc_kprobe(_kprobe_base):
         super().__init__(name, func)
         self.fields = fields
         probe = ' '.join('{!s}={!s}'.format(key,val) for (key, val) in self.fields.items())
-        self.kp = ft.kprobe(event=self.name, function=self.func, probe=probe)
+        self.evt = ft.kprobe(event=self.name, function=self.func, probe=probe)
         self.register()
 
 
@@ -190,8 +197,41 @@  class tc_kretval_probe(_kprobe_base):
         """ Constructor.
         """
         super().__init__(name, func)
-        self.kp = ft.kprobe(event=self.name, function=self.func)
-        self.kp.register()
+        self.evt = ft.kprobe(event=self.name, function=self.func)
+        self.register()
+
+
+class tc_eprobe(_dynevent):
+    def __init__(self, name, target_event, fields):
+        """ Constructor.
+        """
+        super().__init__(name=name)
+        self.target_event = target_event
+        self.fields = fields
+        probe = ' '.join('{!s}={!s}'.format(key,val) for (key, val) in self.fields.items())
+        self.evt = ft.eprobe(event=self.name,
+                            target_system=target_event.system,
+                            target_event=target_event.name,
+                            fetch_fields=probe)
+        self.register()
+
+
+def eprobe_add_ptr_field(name, target_field, field_type, offset=0, fields={}):
+    """ Add a pointer data field to the eprobe descriptor.
+    """
+    probe = '+{0}(${1}):{2}'.format(offset, target_field, field_type)
+    return kprobe_add_raw_field(name=name, probe=probe, fields=fields)
+
+
+def eprobe_add_string_field(name, target_field, offset=0, usr_space=False, fields={}):
+    """ Add a string data field to the eprobe descriptor.
+    """
+    f_type = 'ustring' if usr_space else 'string'
+    return eprobe_add_ptr_field(name=name,
+                                target_field=target_field,
+                                field_type=f_type,
+                                offset=offset,
+                                fields=fields)
 
 
 class tc_hist:
diff --git a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
index 6fdd053..debdd83 100644
--- a/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
+++ b/tracecruncher/tests/1_unit/test_01_ftracepy_unit.py
@@ -507,6 +507,20 @@  class EprobeTestCase(unittest.TestCase):
         ret = ep1.is_enabled(instance=inst)
         self.assertEqual(ret, '0')
 
+class EprobeOopTestCase(unittest.TestCase):
+    def test_eprobe(self):
+        fields = tc.eprobe_add_string_field(name='file',
+                                            target_field='filename',
+                                            usr_space=True)
+        self.assertEqual(fields, {'file': '+0($filename):ustring'})
+
+        if kernel_version < (5, 15):
+            return
+
+        event = tc.tc_event('syscalls', 'sys_enter_openat')
+        eprobe = tc.tc_eprobe(name='opn', target_event=event, fields=fields)
+        self.assertEqual(eprobe.evt.probe(), 'file=+0($filename):ustring')
+
 class TracingOnTestCase(unittest.TestCase):
     def test_ON_OF(self):
         ft.tracing_ON()