From patchwork Mon Jul 12 12:07:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12370845 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9C6AEC07E9C for ; Mon, 12 Jul 2021 12:07:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7D4316101E for ; Mon, 12 Jul 2021 12:07:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229604AbhGLMKQ (ORCPT ); Mon, 12 Jul 2021 08:10:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52176 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233386AbhGLMKP (ORCPT ); Mon, 12 Jul 2021 08:10:15 -0400 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5846EC0613E5 for ; Mon, 12 Jul 2021 05:07:26 -0700 (PDT) Received: by mail-ed1-x52d.google.com with SMTP id s15so27557843edt.13 for ; Mon, 12 Jul 2021 05:07:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=LjB9ZEWHL3gTRLhaqlb/b5s928S8k4Mk06a4ijKwGqY=; b=OI+XpuzKzVT44sIqWFTM5FrH2FXq6/5zonRd+oTioIJ7kWiq4+YIUdqDFHOYgi7ySt otcN0IrV1jTYCKN/3N747SGzOeDpm4dm9RWuNyUXCCeb3umjXcDh7ooLLqt7kmLazjMl 80zH6BgKJgHoZJS+TIMZ+hEhNjlf7qo4PobTz6jqMISvP09dU4Ylv/7QeT3SIh9aMar8 g0YWFOVflImJSAV7mkyjaB7/J/wXl+iGIF7K4XnZpmnxOWRdLanFsecPsomQMOPiVqMH v0yTs1w0wcUGhHmgsbsGrcYhLUPX7uwfX9lBj4jZzKt8tz619O/+DQfo8WE2b0EeRczX OUDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=LjB9ZEWHL3gTRLhaqlb/b5s928S8k4Mk06a4ijKwGqY=; b=a6RxkTb1+uDOtCSo9CWfNBVIQJ5bMN4XsismbYcjayfCntMrBdK8Z+KBYMrrkZP/f9 r0LfOmjpZdxsf40r90ypVDgvQiWRpDH+nbkaPiSRoaWb6InTVM1Qmoq8kV5Bcxb2gg6s xmEzFJES68/RrIugd8LA/fxZXx+4Vmvblv41xS5p//3XS93Zptuky3cnOyxJIvB9gvBb rLTM52rwqMdBbdCueT5z9Qlc3fOhXsK7OFQosBpB/52sFFzblJgX2wixIQ4asmCSWOiQ q4mI/3SR7G39ZSpgYNnWKLE2Il92WvSzti+wX6F5nf1oRgF90quDmpjHhkj1SZjbwOBN Jq3w== X-Gm-Message-State: AOAM5327eGDlJwucNe/fjJUqDzAKrGpZXm+id7VKUDPAJzHTt/u8YUuV zl1g3iyqXlB+bbX8Nzu+E5C3571qgx8= X-Google-Smtp-Source: ABdhPJy3yhbNn7YJAusayrbBk1XWDBjQrj3c2L3XMnE2zQycU1EEFEgXlE/MV+kD42ZXoRwQQy4RLA== X-Received: by 2002:a50:8d54:: with SMTP id t20mr13577978edt.288.1626091644594; Mon, 12 Jul 2021 05:07:24 -0700 (PDT) Received: from localhost.localdomain ([95.87.199.98]) by smtp.gmail.com with ESMTPSA id ee29sm2900809edb.39.2021.07.12.05.07.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jul 2021 05:07:24 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: linux-trace-devel@vger.kernel.org Cc: "Yordan Karadzhov (VMware)" Subject: [PATCH v2 1/3] trace-cruncher: Add support for Kprobes Date: Mon, 12 Jul 2021 15:07:04 +0300 Message-Id: <20210712120706.221921-2-y.karadz@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210712120706.221921-1-y.karadz@gmail.com> References: <20210712120706.221921-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Kprobes is a built-in debugging mechanism for the Linux kernel, which can be used extract monitoring data from a running production system. Here we add to trace-cruncher a basic support for using Kprobes. Signed-off-by: Yordan Karadzhov (VMware) --- src/ftracepy-utils.c | 366 ++++++++++++++++++++++++-- src/ftracepy-utils.h | 30 +++ src/ftracepy.c | 55 ++++ tests/1_unit/test_01_ftracepy_unit.py | 57 ++++ 4 files changed, 490 insertions(+), 18 deletions(-) diff --git a/src/ftracepy-utils.c b/src/ftracepy-utils.c index 91a319e..dfb0669 100644 --- a/src/ftracepy-utils.c +++ b/src/ftracepy-utils.c @@ -100,6 +100,7 @@ PyObject *PyTepEvent_parse_record_field(PyTepEvent* self, PyObject *args, PyObject *kwargs) { struct tep_format_field *field; + int field_offset, field_size; const char *field_name; PyTepRecord *record; @@ -124,11 +125,24 @@ PyObject *PyTepEvent_parse_record_field(PyTepEvent* self, PyObject *args, return NULL; } - if (!field->size) + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + unsigned long long val; + + val = tep_read_number(self->ptrObj->tep, + record->ptrObj->data + field->offset, + field->size); + field_offset = val & 0xffff; + field_size = val >> 16; + } else { + field_offset = field->offset; + field_size = field->size; + } + + if (!field_size) return PyUnicode_FromString("(nil)"); if (field->flags & TEP_FIELD_IS_STRING) { - char *val_str = record->ptrObj->data + field->offset; + char *val_str = record->ptrObj->data + field_offset; return PyUnicode_FromString(val_str); } else if (is_number(field)) { unsigned long long val; @@ -136,7 +150,7 @@ PyObject *PyTepEvent_parse_record_field(PyTepEvent* self, PyObject *args, tep_read_number_field(field, record->ptrObj->data, &val); return PyLong_FromLong(val); } else if (field->flags & TEP_FIELD_IS_POINTER) { - void *val = record->ptrObj->data + field->offset; + void *val = record->ptrObj->data + field_offset; char ptr_string[11]; sprintf(ptr_string, "%p", val); @@ -1058,14 +1072,33 @@ PyObject *PyFtrace_disable_events(PyObject *self, PyObject *args, Py_RETURN_NONE; } +static PyObject *event_is_enabled(struct tracefs_instance *instance, + const char *system, const char *event) +{ + char *file, *val; + PyObject *ret; + + if (!get_event_enable_file(instance, system, event, &file)) + return NULL; + + if (read_from_file(instance, file, &val) <= 0) + return NULL; + + trim_new_line(val); + ret = PyUnicode_FromString(val); + + free(file); + free(val); + + return ret; +} + PyObject *PyFtrace_event_is_enabled(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"instance", "system", "event", NULL}; const char *instance_name, *system, *event; struct tracefs_instance *instance; - char *file, *val; - PyObject *ret; instance_name = system = event = NO_ARG; if (!PyArg_ParseTupleAndKeywords(args, @@ -1081,19 +1114,7 @@ PyObject *PyFtrace_event_is_enabled(PyObject *self, PyObject *args, if (!get_optional_instance(instance_name, &instance)) return false; - if (!get_event_enable_file(instance, system, event, &file)) - return NULL; - - if (read_from_file(instance, file, &val) <= 0) - return NULL; - - trim_new_line(val); - ret = PyUnicode_FromString(val); - - free(file); - free(val); - - return ret; + return event_is_enabled(instance, system, event); } PyObject *PyFtrace_set_event_filter(PyObject *self, PyObject *args, @@ -1472,6 +1493,314 @@ PyObject *PyFtrace_supported_options(PyObject *self, PyObject *args, return get_option_list(instance, false); } +static void *kprobe_root = NULL; + +static int kprobe_compare(const void *a, const void *b) +{ + const char *ca = (const char *) a; + const char *cb = (const char *) b; + + return strcmp(ca, cb); +} + +#define TC_SYS "tcrunch" + +PyObject *PyFtrace_tc_event_system(PyObject *self) +{ + return PyUnicode_FromString(TC_SYS); +} + +static int unregister_kprobe(const char *event) +{ + return tracefs_kprobe_clear_probe(TC_SYS, event, true); +} + +void kprobe_free(void *kp) +{ + char *event = kp; + + if (unregister_kprobe(event) < 0) + fprintf(stderr, "\ntfs_error: Failed to unregister kprobe \'%s\'.\n", + event); + + free(kp); +} + +static void destroy_all_kprobes(void) +{ + tdestroy(kprobe_root, kprobe_free); + kprobe_root = NULL; +} + +bool store_new_kprobe(const char *event) +{ + char *ptr = strdup(event); + char **val; + + if (!ptr) { + MEM_ERROR; + return false; + } + + val = tsearch(ptr, &kprobe_root, kprobe_compare); + if (!val || strcmp(*val, ptr) != 0) { + PyErr_Format(TFS_ERROR, "Failed to store new kprobe \'%s\'.", + event); + return false; + } + + return true; +} + +PyObject *PyFtrace_register_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = {"event", "function", "probe", NULL}; + const char *event, *function, *probe; + + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "sss", + kwlist, + &event, + &function, + &probe)) { + return NULL; + } + + if (tracefs_kprobe_raw(TC_SYS, event, function, probe) < 0) { + PyErr_Format(TFS_ERROR, "Failed to register kprobe \'%s\'.", + event); + return NULL; + } + + if (!store_new_kprobe(event)) + return NULL; + + Py_RETURN_NONE; +} + +PyObject *PyFtrace_register_kretprobe(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = {"event", "function", "probe", NULL}; + const char *event, *function, *probe = "$retval"; + + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "ss|s", + kwlist, + &event, + &function, + &probe)) { + return NULL; + } + + if (tracefs_kretprobe_raw(TC_SYS, event, function, probe) < 0) { + PyErr_Format(TFS_ERROR, "Failed to register kretprobe \'%s\'.", + event); + return NULL; + } + + if (!store_new_kprobe(event)) + return NULL; + + Py_RETURN_NONE; +} + +PyObject *PyFtrace_unregister_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = {"event", "force", NULL}; + const char *event; + int force = false; + + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "s|p", + kwlist, + &event, + &force)) { + return NULL; + } + + if (is_all(event)) { + if (force) { + /* Clear all register kprobes. */ + if (tracefs_kprobe_clear_all(force) < 0) + goto fail; + } else { + /* + * Clear only the kprobes registered by + * trace-cruncher. + */ + destroy_all_kprobes(); + } + } else { + tdelete(event, &kprobe_root, kprobe_compare); + if (unregister_kprobe(event) < 0) + goto fail; + } + + Py_RETURN_NONE; + + fail: + PyErr_Format(TFS_ERROR, "Failed to unregister kprobe \'%s\'.", event); + return NULL; +} + +PyObject *PyFtrace_registered_kprobe_names(PyObject *self) +{ + char **list = tracefs_get_kprobes(TRACEFS_ALL_KPROBES); + return tfs_list2py_list(list); +} + +PyObject *PyFtrace_registered_kprobes(PyObject *self) +{ + const char *file = "kprobe_events"; + PyObject *list = PyList_New(0); + char *probes, *token; + int size; + + size = read_from_file(NULL, file, &probes); + if (size < 0) + return NULL; + + if (size == 0 || !probes) + return list; + + token = strtok(probes, "\n"); + while (token != NULL) { + PyList_Append(list, PyUnicode_FromString(token)); + token = strtok(NULL, "\n"); + } + + return list; +} + +PyObject *PyFtrace_set_kprobe_filter(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + const char *instance_name = NO_ARG, *event, *filter; + struct tracefs_instance *instance; + char path[PATH_MAX]; + + static char *kwlist[] = {"event", "filter", "instance", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "ss|s", + kwlist, + &event, + &filter, + &instance_name)) { + return NULL; + } + + if (!get_optional_instance(instance_name, &instance)) + return NULL; + + sprintf(path, "events/%s/%s/filter", TC_SYS, event); + if (!write_to_file_and_check(instance, path, filter)) { + PyErr_SetString(TFS_ERROR, "Failed to set kprobe filter."); + return NULL; + } + + Py_RETURN_NONE; +} + +PyObject *PyFtrace_clear_kprobe_filter(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + const char *instance_name = NO_ARG, *event; + struct tracefs_instance *instance; + char path[PATH_MAX]; + + static char *kwlist[] = {"event", "instance", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "s|s", + kwlist, + &event, + &instance_name)) { + return NULL; + } + + if (!get_optional_instance(instance_name, &instance)) + return NULL; + + sprintf(path, "events/%s/%s/filter", TC_SYS, event); + if (!write_to_file(instance, path, OFF)) { + PyErr_SetString(TFS_ERROR, "Failed to clear kprobe filter."); + return NULL; + } + + Py_RETURN_NONE; +} + +static bool enable_kprobe(PyObject *self, PyObject *args, PyObject *kwargs, + bool enable) +{ + static char *kwlist[] = {"event", "instance", NULL}; + struct tracefs_instance *instance; + const char *instance_name, *event; + + instance_name = event = NO_ARG; + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "s|s", + kwlist, + &event, + &instance_name)) { + return false; + } + + if (!get_optional_instance(instance_name, &instance)) + return false; + + return event_enable_disable(instance, TC_SYS, event, enable); +} + +PyObject *PyFtrace_enable_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + if (!enable_kprobe(self, args, kwargs, true)) + return NULL; + + Py_RETURN_NONE; +} + +PyObject *PyFtrace_disable_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + if (!enable_kprobe(self, args, kwargs, false)) + return NULL; + + Py_RETURN_NONE; +} + +PyObject *PyFtrace_kprobe_is_enabled(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = {"event", "instance", NULL}; + struct tracefs_instance *instance; + const char *instance_name, *event; + + instance_name = event = NO_ARG; + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "s|s", + kwlist, + &event, + &instance_name)) { + return NULL; + } + + if (!get_optional_instance(instance_name, &instance)) + return NULL; + + return event_is_enabled(instance, TC_SYS, event); +} + static bool set_fork_options(struct tracefs_instance *instance, bool enable) { if (enable) { @@ -1865,5 +2194,6 @@ PyObject *PyFtrace_hook2pid(PyObject *self, PyObject *args, PyObject *kwargs) void PyFtrace_at_exit(void) { + destroy_all_kprobes(); destroy_all_instances(); } diff --git a/src/ftracepy-utils.h b/src/ftracepy-utils.h index 3699aaa..d826427 100644 --- a/src/ftracepy-utils.h +++ b/src/ftracepy-utils.h @@ -125,6 +125,36 @@ PyObject *PyFtrace_supported_options(PyObject *self, PyObject *args, PyObject *PyFtrace_enabled_options(PyObject *self, PyObject *args, PyObject *kwargs); +PyObject *PyFtrace_tc_event_system(PyObject *self); + +PyObject *PyFtrace_register_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_register_kretprobe(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_unregister_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_registered_kprobes(PyObject *self); + +PyObject *PyFtrace_registered_kprobe_names(PyObject *self); + +PyObject *PyFtrace_set_kprobe_filter(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_clear_kprobe_filter(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_enable_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_disable_kprobe(PyObject *self, PyObject *args, + PyObject *kwargs); + +PyObject *PyFtrace_kprobe_is_enabled(PyObject *self, PyObject *args, + PyObject *kwargs); + PyObject *PyFtrace_trace_process(PyObject *self, PyObject *args, PyObject *kwargs); diff --git a/src/ftracepy.c b/src/ftracepy.c index 5dd61e4..e5fcd54 100644 --- a/src/ftracepy.c +++ b/src/ftracepy.c @@ -214,6 +214,61 @@ static PyMethodDef ftracepy_methods[] = { METH_VARARGS | METH_KEYWORDS, "Gat a list of all supported options." }, + {"tc_event_system", + (PyCFunction) PyFtrace_tc_event_system, + METH_NOARGS, + "Get the name of the event system used by trace-cruncher." + }, + {"register_kprobe", + (PyCFunction) PyFtrace_register_kprobe, + METH_VARARGS | METH_KEYWORDS, + "Define a kprobe." + }, + {"register_kretprobe", + (PyCFunction) PyFtrace_register_kretprobe, + METH_VARARGS | METH_KEYWORDS, + "Define a kretprobe." + }, + {"unregister_kprobe", + (PyCFunction) PyFtrace_unregister_kprobe, + METH_VARARGS | METH_KEYWORDS, + "Define a kprobe." + }, + {"registered_kprobes", + (PyCFunction) PyFtrace_registered_kprobes, + METH_NOARGS, + "Get all registered kprobes." + }, + {"registered_kprobe_names", + (PyCFunction) PyFtrace_registered_kprobe_names, + METH_NOARGS, + "Get the names of all registered kprobes." + }, + {"set_kprobe_filter", + (PyCFunction) PyFtrace_set_kprobe_filter, + METH_VARARGS | METH_KEYWORDS, + "Define a filter for a kprobe." + }, + {"clear_kprobe_filter", + (PyCFunction) PyFtrace_clear_kprobe_filter, + METH_VARARGS | METH_KEYWORDS, + "Clear the filter of a kprobe." + }, + {"enable_kprobe", + (PyCFunction) PyFtrace_enable_kprobe, + METH_VARARGS | METH_KEYWORDS, + "Enable kprobe event." + }, + {"disable_kprobe", + (PyCFunction) PyFtrace_disable_kprobe, + METH_VARARGS | METH_KEYWORDS, + "Disable kprobe event." + }, + {"kprobe_is_enabled", + (PyCFunction) PyFtrace_kprobe_is_enabled, + METH_VARARGS | METH_KEYWORDS, + "Check if kprobe event is enabled." + }, {"trace_process", (PyCFunction) PyFtrace_trace_process, METH_VARARGS | METH_KEYWORDS, diff --git a/tests/1_unit/test_01_ftracepy_unit.py b/tests/1_unit/test_01_ftracepy_unit.py index e11c034..0d62da2 100644 --- a/tests/1_unit/test_01_ftracepy_unit.py +++ b/tests/1_unit/test_01_ftracepy_unit.py @@ -441,6 +441,63 @@ class OptionsTestCase(unittest.TestCase): ft.destroy_all_instances() +class KprobeTestCase(unittest.TestCase): + def test_register_kprobe(self): + evt1 = 'mkdir' + evt1_func = 'do_mkdirat' + evt1_prove = 'path=+u0($arg2):ustring' + evt2 = 'open' + evt2_func = 'do_sys_openat2' + evt2_prove = 'file=+u0($arg2):ustring' + + ft.register_kprobe(event=evt1, function=evt1_func, + probe=evt1_prove) + all_kprobes = ft.registered_kprobes() + self.assertEqual(len(all_kprobes), 1) + self.assertTrue(evt1 in all_kprobes[0]) + self.assertTrue(evt1_func in all_kprobes[0]) + self.assertTrue(evt1_prove in all_kprobes[0]) + + ft.unregister_kprobe(event=evt1) + all_kprobes = ft.registered_kprobes() + self.assertEqual(len(all_kprobes), 0) + + ft.register_kprobe(event=evt1, function=evt1_func, + probe=evt1_prove) + ft.register_kprobe(event=evt2, function=evt2_func, + probe=evt2_prove) + all_kprobes = ft.registered_kprobes() + self.assertEqual(len(all_kprobes), 2) + self.assertTrue(evt1 in all_kprobes[0]) + self.assertTrue(evt1_func in all_kprobes[0]) + self.assertTrue(evt1_prove in all_kprobes[0]) + self.assertTrue(evt2 in all_kprobes[1]) + self.assertTrue(evt2_func in all_kprobes[1]) + self.assertTrue(evt2_prove in all_kprobes[1]) + + ft.unregister_kprobe(event='ALL') + all_kprobes = ft.registered_kprobes() + self.assertEqual(len(all_kprobes), 0) + + + def test_enable_kprobe(self): + evt1 = 'mkdir' + evt1_func = 'do_mkdirat' + evt1_prove = 'path=+u0($arg2):ustring' + + ft.register_kprobe(event=evt1, function=evt1_func, + probe=evt1_prove) + ft.create_instance(instance_name) + ft.enable_kprobe(instance=instance_name, event=evt1) + ret = ft.kprobe_is_enabled(instance=instance_name, event=evt1) + self.assertEqual(ret, '1') + + ft.disable_kprobe(instance=instance_name, event=evt1) + ret = ft.kprobe_is_enabled(instance=instance_name, event=evt1) + self.assertEqual(ret, '0') + + ft.unregister_kprobe(event='ALL') + ft.destroy_all_instances() class TracingOnTestCase(unittest.TestCase): def test_ON_OF(self): From patchwork Mon Jul 12 12:07:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12370849 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BE42BC07E9A for ; Mon, 12 Jul 2021 12:07:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A55136101E for ; Mon, 12 Jul 2021 12:07:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233386AbhGLMKQ (ORCPT ); Mon, 12 Jul 2021 08:10:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52182 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233391AbhGLMKP (ORCPT ); Mon, 12 Jul 2021 08:10:15 -0400 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 31D8DC0613E8 for ; Mon, 12 Jul 2021 05:07:27 -0700 (PDT) Received: by mail-ed1-x52d.google.com with SMTP id ec55so2769050edb.1 for ; Mon, 12 Jul 2021 05:07:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=axU+xjMftFNU2eR+Ctufg4ij0wvLzt7ZOIt23NLj/Hw=; b=fBpoV4ZcotPaHuy9xvONEV2zsr7D6UJPtpyMkJig4d9He+iYqMvVq2Z9W4+DEaVdTV JZ/VB1w1XwWuUpH584kDd4UOoGrx8Ah4r4i5Nel9BYdFqd8L81DpCRRcLLiuzLC4HGTd IcqnOl/3H6NL3ISPpnQZY1DdX/b4QBww0HnMCnH2GMIvQUhQVAnYkweT9lRY5D6tTrS8 poluXsgw+i9J0faaza9vLJXa4bggujBxz46A3c8LbpC3nV+5+UDhysnwGEdCORtdXelj ACU0M9bkboKhBssJ/ARnTI8SJlAiG2OoAuC/pN1hSUaKTUv8te/pGa3tk68+ES9go++e EepA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=axU+xjMftFNU2eR+Ctufg4ij0wvLzt7ZOIt23NLj/Hw=; b=AIkIa8AanlZwxQtYjnzWwZpmDNHj6hQ7zTjIDo7LW/uhOBrRyJxoqzUmjhKhG5SAIo lFKTLEdoudM5Dj1YVWI4bXeMbYG1v0go9Z3EQ1QoAxGGleYfF7GKY91NUinliSviSkz4 nbX4cSl5l+Yb8zqv3g3C4o/7gn3686y5vKuW+pUrweh4jtvQ5chZuLKohhmePwDwuUJ/ XpfLwyue7lrGoeVHvRC81Eq6HRHfVydWB2D9TaCGznC8OiS3L6b0TjFxJ+gbPvf6RgCV QbPCL78v8J+yKcUNKcft0N9mmh7ijBwVNWgzKMnYulxf/c9csk3cIbp/jcr2L+wbFGJ9 4B9w== X-Gm-Message-State: AOAM530hAE8RvWlRGNBj2hyDWgGHJno6q5F+SdOICr3g25wzXNVA+knZ FiM2fIwt/G7Mo8iRDxszaW4b7lOdfpU= X-Google-Smtp-Source: ABdhPJxpHNSwRNTrzhl2GYOBMWKkvEGv+l6w1BI8mfa7Wjqfd+xLL+FVLof5IsEN1W21TwjksA6nhg== X-Received: by 2002:aa7:cd96:: with SMTP id x22mr35881159edv.102.1626091645614; Mon, 12 Jul 2021 05:07:25 -0700 (PDT) Received: from localhost.localdomain ([95.87.199.98]) by smtp.gmail.com with ESMTPSA id ee29sm2900809edb.39.2021.07.12.05.07.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jul 2021 05:07:25 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: linux-trace-devel@vger.kernel.org Cc: "Yordan Karadzhov (VMware)" Subject: [PATCH v2 2/3] trace-cruncher: Add events to utils Date: Mon, 12 Jul 2021 15:07:05 +0300 Message-Id: <20210712120706.221921-3-y.karadz@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210712120706.221921-1-y.karadz@gmail.com> References: <20210712120706.221921-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org Define a hierarchy of Python classes, to be used for easy manipulation of Staic events and Kprobes. Signed-off-by: Yordan Karadzhov (VMware) --- tracecruncher/ft_utils.py | 182 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/tracecruncher/ft_utils.py b/tracecruncher/ft_utils.py index eae161c..5b4f2f2 100644 --- a/tracecruncher/ft_utils.py +++ b/tracecruncher/ft_utils.py @@ -6,6 +6,7 @@ Copyright 2019 VMware Inc, Yordan Karadzhov (VMware) import sys import time +import ctypes from . import ftracepy as ft @@ -17,3 +18,184 @@ def find_event_id(system, event): tep.init_local(dir=ft.dir(), systems=[system]); return tep.get_event(system=system, name=event).id() + + +class event: + def __init__(self, system, name, static=True): + """ Constructor. + """ + self.system = system + self.name = name + self.instance_list = [] + if static: + self.evt_id = find_event_id(system, name) + else: + self.evt_id = -1 + + def id(self): + """ Retrieve the unique ID of the kprobe event. + """ + return int(self.evt_id) + + def enable(self, instance=None): + """ Enable this event. + """ + if instance is None: + ft.enable_event(system=self.system, event=self.name) + self.instance_list.append('top') + else: + ft.enable_event(instance=instance, system=self.system, event=self.name) + self.instance_list.append(instance) + + self.instance_list = list(set(self.instance_list)) + + def disable(self, instance=None): + """ Disable this event. + """ + if instance is None: + ft.disable_event(system=self.system, event=self.name) + self.instance_list.remove('top') + else: + ft.disable_event(instance=instance,system=self.system, event=self.name) + self.instance_list.remove(instance) + + def set_filter(self, filter, instance=None): + """ Define a filter for this event. + """ + if instance is None: + ft.set_event_filter(system=self.system, + event=self.name, + filter=filter) + else: + ft.set_event_filter(instance=instance, + system=self.system, + event=self.name, + filter=filter) + + def clear_filter(self, instance=None): + """ Define the filter for this event. + """ + if instance is None: + ft.clear_event_filter(system=self.system, + event=self.name) + else: + ft.clear_event_filter(instance=instance, + system=self.system, + event=self.name) + + +class kprobe_base(event): + def __init__(self, name, func=''): + """ Constructor. + """ + super().__init__(system=ft.tc_event_system(), name=name, static=False) + self.func = func + + def set_function(self, name): + """ Set the name of the function to be traced. + """ + self.func = name + + def unregister(self): + """ Unregister this probe from Ftrace. + """ + inst_list = self.instance_list.copy() + for instance in inst_list: + self.disable(instance) + + ft.unregister_kprobe(event=self.name); + + +class kprobe(kprobe_base): + def __init__(self, name, func=''): + """ Constructor. + """ + super().__init__(name, func) + self.fields = {} + + def add_raw_field(self, name, probe): + """ Add a raw definition of a data field to this probe. + """ + self.fields[str(name)] = str(probe) + + def add_arg(self, name, param_id, param_type): + """ Add a function parameter data field to this probe. + """ + probe = '$arg{0}:{1}'.format(param_id, param_type) + self.add_raw_field(name, probe) + + def add_ptr_arg(self, name, param_id, param_type, offset=0): + """ Add a pointer function parameter data field to this probe. + """ + probe = '+{0}($arg{1}):{2}'.format(offset, param_id, param_type) + self.add_raw_field(name, probe) + + def add_array_arg(self, name, param_id, param_type, offset=0, size=-1): + """ Add a array parameter data field to this probe. + """ + if size < 0: + size = 10 + + ptr_size = ctypes.sizeof(ctypes.c_voidp) + for i in range(size): + field_name = name + str(i) + probe = '+{0}(+{1}'.format(offset, i * ptr_size) + probe += '($arg{0})):{1}'.format(param_id, param_type) + self.add_raw_field(field_name, probe) + + def add_string_arg(self, name, param_id, offset=0, usr_space=False): + """ Add a pointer function parameter data field to this probe. + """ + p_type = 'ustring' if usr_space else 'string' + self.add_ptr_arg(name=name, + param_id=param_id, + param_type=p_type, + offset=offset) + + def add_string_array_arg(self, name, param_id, offset=0, usr_space=False, size=-1): + """ Add a string array parameter data field to this probe. + """ + p_type = 'ustring' if usr_space else 'string' + self.add_array_arg(name=name, + param_id=param_id, + param_type=p_type, + offset=offset, + size=size) + + def register(self): + """ Register this probe to Ftrace. + """ + probe = ' '.join('{!s}={!s}'.format(key,val) for (key, val) in self.fields.items()) + + ft.register_kprobe(event=self.name, function=self.func, probe=probe); + self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name) + + +def parse_record_array_field(event, record, field, size=-1): + """ Register this probe to Ftrace. + """ + if size < 0: + size = 10 + + arr = [] + for i in range(size): + field_name = field + str(i) + val = event.parse_record_field(record=record, field=field_name) + if (val == '(nil)'): + break + arr.append(val) + + return arr + + +class kretval_probe(kprobe_base): + def __init__(self, name, func=''): + """ Constructor. + """ + super().__init__(name, func) + + def register(self): + """ Register this probe to Ftrace. + """ + ft.register_kprobe(event=self.name, function=self.func); + self.evt_id = find_event_id(system=ft.tc_event_system(), event=self.name) From patchwork Mon Jul 12 12:07:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yordan Karadzhov X-Patchwork-Id: 12370847 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43A6CC11F67 for ; Mon, 12 Jul 2021 12:07:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2B93961004 for ; Mon, 12 Jul 2021 12:07:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233266AbhGLMKR (ORCPT ); Mon, 12 Jul 2021 08:10:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233438AbhGLMKR (ORCPT ); Mon, 12 Jul 2021 08:10:17 -0400 Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5947BC0613DD for ; Mon, 12 Jul 2021 05:07:28 -0700 (PDT) Received: by mail-ed1-x52b.google.com with SMTP id k27so3992529edk.9 for ; Mon, 12 Jul 2021 05:07:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=f5g39+qOjCuYpw84giJ6IYfWYCyAba3AS6qJtwKdxKA=; b=R9fSt75gH8sTfhzJakPASTL2Wo/QCPSMd2H6af3k5Xfjgz0AUEnKGd6LmCXPJPRd6P kZ6yyJtkK2eP2FvvWQdqcqpSU66xv1Wyc5JUlkkdiBD89Y/wf4ZzCWCafSd2XSQo4GCH srSQudGD3he+ap7+YPF/x3UuRJDikqjeUC9b8VpoO2bWQtaWkcdYEI0TP/LclMMxjWh3 7brihxPUiawgGqvX26Tnnfc778rk4y2HP0b36uIwXLBoMqGGkqrbEyx+ynhyTXg2Uygj Nqq3zn7K0DEGqNcK4I2pzpDP8dACKwwymcb318/FMNZQrHBTOLz8SFTYVVze4pbwiiPn nA2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=f5g39+qOjCuYpw84giJ6IYfWYCyAba3AS6qJtwKdxKA=; b=rabxo5169qMydk2cE58joTnOBVlzBwlJePDBUOrR2L0yEEgswMaI7ZSsdT5SwGQpE4 8n9Eu6o/f20lDYsvnbRu7KPQc0K8uXot/61RmMJd8hMSSXhA7I85epNqLvfp/nSg3FuF KvOBmnoUE+vzyhLoElArcCeNHspE6D6vPtX2uEv6HhzEViWt8kBv+pCbrZ6A6f4PsiJJ 98ynAI1sm1gIn0g253mdJ0lSbDaRb3x+CtoP6TxNYNDrAfOLVEEFt4R4x+ury58MV2wI RnKi0wyzST2jZbL1O8izDn0r1nA3hXHk7LdwXhajWvS/LoFYGy7k0ZLLwzwRACUpygut RLPQ== X-Gm-Message-State: AOAM533RsESOvzI4F2WoM+GhO7wuuGG+B7nuxPdWFbGezV6PKURFU7wV Va7kXYrwZg+JCoye4vVLdljF5LWaRs8= X-Google-Smtp-Source: ABdhPJwErLrIzU/U6VrFawDeCPtQv+41iz51B4u3Qm/NzKDtgDMLWAHYxgzmpiC0Zhrgej9Xa/VYaw== X-Received: by 2002:aa7:c5c3:: with SMTP id h3mr1277123eds.376.1626091646788; Mon, 12 Jul 2021 05:07:26 -0700 (PDT) Received: from localhost.localdomain ([95.87.199.98]) by smtp.gmail.com with ESMTPSA id ee29sm2900809edb.39.2021.07.12.05.07.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jul 2021 05:07:26 -0700 (PDT) From: "Yordan Karadzhov (VMware)" To: linux-trace-devel@vger.kernel.org Cc: "Yordan Karadzhov (VMware)" Subject: [PATCH v2 3/3] trace-cruncher: Add Kprobe example Date: Mon, 12 Jul 2021 15:07:06 +0300 Message-Id: <20210712120706.221921-4-y.karadz@gmail.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210712120706.221921-1-y.karadz@gmail.com> References: <20210712120706.221921-1-y.karadz@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-trace-devel@vger.kernel.org This is a very basic example that aims to demonstrate the usage of Kprobes in trace-cruncher. Signed-off-by: Yordan Karadzhov (VMware) --- examples/kprobe_open.py | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 examples/kprobe_open.py diff --git a/examples/kprobe_open.py b/examples/kprobe_open.py new file mode 100755 index 0000000..f8d4d8b --- /dev/null +++ b/examples/kprobe_open.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +""" +SPDX-License-Identifier: CC-BY-4.0 + +Copyright (C) 2021 VMware Inc, Yordan Karadzhov (VMware) +""" + +import sys + +import tracecruncher.ftracepy as ft +import tracecruncher.ft_utils as tc + +open_probe = tc.kprobe(name='open', func='do_sys_openat2') + +open_probe.add_string_arg(name='file', param_id=2) + +open_probe.add_ptr_arg(name='flags', + param_id=3, + param_type='x64') + +open_probe.add_ptr_arg(name='mode', + param_id=3, + param_type='x64', + offset=8) + +open_probe.register() + +def callback(event, record): + if event.id() == open_probe.id(): + file_name = event.parse_record_field(record=record, field='file') + flags = event.parse_record_field(record, 'flags') + mode = event.parse_record_field(record, 'mode') + print('file: {0} (flags: {1}; mode: {2})'.format(file_name, hex(flags), hex(mode))) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print('Usage: ', sys.argv[0], ' [PROCESS]') + sys.exit(1) + + inst = ft.create_instance(tracing_on=False) + open_probe.enable(instance=inst) + ft.trace_process(instance=inst, argv=sys.argv[1:])