lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240919215107.2263552-3-stefan.ene@intel.com>
Date: Thu, 19 Sep 2024 14:51:02 -0700
From: Stefan@....codeaurora.org, Ene@....codeaurora.org
To: peterz@...radead.org,
	mingo@...hat.com,
	acme@...nel.org,
	namhyung@...nel.org,
	mark.rutland@....com,
	alexander.shishkin@...ux.intel.com,
	jolsa@...nel.org,
	irogers@...gle.com,
	adrian.hunter@...el.com,
	kan.liang@...ux.intel.com,
	linux-perf-users@...r.kernel.org,
	linux-kernel@...r.kernel.org
Cc: vinicius.gomes@...el.com,
	stefan.ene@...el.com,
	stef_an_ene@...look.com
Subject: [RFC v1 1/3] C and Rust support for perf script

From: Stefan Ene <stefan.ene@...el.com>

[PATCH 1/3] add the new perf script option (--new_script) and related
 changes

---
 tools/perf/builtin-script.c  |  22 +-
 tools/perf/util/Build        |   1 +
 tools/perf/util/new_script.c | 376 +++++++++++++++++++++++++++++++++++
 tools/perf/util/new_script.h |  54 +++++
 4 files changed, 452 insertions(+), 1 deletion(-)
 create mode 100644 tools/perf/util/new_script.c
 create mode 100644 tools/perf/util/new_script.h

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c16224b1fef3..e91a1e2481bb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -63,6 +63,7 @@
 #include "util/util.h"
 #include "util/cgroup.h"
 #include "perf.h"
+#include "util/new_script.h"
 
 #include <linux/ctype.h>
 #ifdef HAVE_LIBTRACEEVENT
@@ -88,6 +89,7 @@ static struct perf_stat_config	stat_config;
 static int			max_blocks;
 static bool			native_arch;
 static struct dlfilter		*dlfilter;
+static struct new_script	*new_struct;
 static int			dlargc;
 static char			**dlargv;
 
@@ -3898,6 +3900,7 @@ int cmd_script(int argc, const char **argv)
 	struct utsname uts;
 	char *script_path = NULL;
 	const char *dlfilter_file = NULL;
+	const char *new_script_file = NULL;
 	const char **__argv;
 	int i, j, err = 0;
 	struct perf_script script = {
@@ -3954,6 +3957,7 @@ int cmd_script(int argc, const char **argv)
 	OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
 		   "generate perf-script.xx script in specified language"),
 	OPT_STRING(0, "dlfilter", &dlfilter_file, "file", "filter .so file name"),
+	OPT_STRING(0, "new_script", &new_script_file, "file", "specify .so file name"),
 	OPT_CALLBACK(0, "dlarg", NULL, "argument", "filter argument",
 		     add_dlarg),
 	OPT_STRING('i', "input", &input_name, "file", "input file name"),
@@ -4355,6 +4359,21 @@ int cmd_script(int argc, const char **argv)
 		goto out_delete;
 	}
 #endif
+
+	if (new_script_file) {
+		new_struct = new_script__new(new_script_file);
+
+		if (!new_struct) {
+			perror("cannot create new_script objects\n");
+			goto out_delete;
+		}
+		if (new_script__start(new_struct, &data) < 0) {
+			perror("cannot start new_script object\n");
+			goto out_delete;  
+		}
+		goto out_delete;
+	}
+
 	if (generate_script_lang) {
 		struct stat perf_stat;
 		int input;
@@ -4458,7 +4477,8 @@ int cmd_script(int argc, const char **argv)
 	if (script_started)
 		cleanup_scripting();
 	dlfilter__cleanup(dlfilter);
+	new_script__cleanup(new_struct);
 	free_dlarg();
 out:
 	return err;
-}
+}
\ No newline at end of file
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 0f18fe81ef0b..386cdd0fe13c 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -140,6 +140,7 @@ perf-util-y += parse-sublevel-options.o
 perf-util-y += term.o
 perf-util-y += help-unknown-cmd.o
 perf-util-y += dlfilter.o
+perf-util-y += new_script.o
 perf-util-y += mem-events.o
 perf-util-y += mem-info.o
 perf-util-y += vsprintf.o
diff --git a/tools/perf/util/new_script.c b/tools/perf/util/new_script.c
new file mode 100644
index 000000000000..ff3234b20738
--- /dev/null
+++ b/tools/perf/util/new_script.c
@@ -0,0 +1,376 @@
+// Stefan Ene's code, under Intel - Linux Kernel Team
+/*
+ * new_script.c: code for new scripting object allowing C and Rust event processing
+ * 
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+#include <linux/types.h>
+#include <perf/event.h>
+
+#include "data.h"
+#include "sample.h" 
+#include "header.h" 
+#include "new_script.h"
+#include "ordered-events.h"
+
+// rust lib
+#include "new_script_rs_lib.h"
+
+
+#define PATH_MAX 4096
+#define MMAP_SIZE (32 * 1024 * 1024ULL)
+#define	EINVAL		22	/* Invalid argument */
+
+
+static char *
+find_new_script(const char* file)
+{
+    char path[PATH_MAX];
+
+    if (strchr(file, '/'))
+		goto out;
+
+    if (!access(file, R_OK)) {
+        snprintf(path, sizeof(path), "./%s", file);
+		file = path;
+    }
+
+out:
+    return strdup(file);
+}
+
+
+static int
+new_script_open(struct new_script* s)
+{
+    void (*initialize)(struct new_script*);
+
+    s->handle = dlopen(s->file, RTLD_NOW);
+    if (!s->handle)
+        return -1;
+
+    initialize = (void (*)(struct new_script*))dlsym(s->handle, "initialize_new_script");
+
+    if (!initialize) {
+        dlclose(s->handle);
+        return -1;
+    }
+    initialize(s);
+
+    return 0;
+}
+
+
+static int 
+new_script__init(struct new_script *s, const char *file)
+{
+    memset(s, 0, sizeof(*s));
+    s->file = find_new_script(file);    // not freed since file string used somewhere else
+    if (!s->file)
+        return -1;
+    
+    return 0;
+}
+
+
+struct new_script *
+new_script__new(const char *file)
+{
+    struct new_script *s = malloc(sizeof(*s));
+    if(!s)
+        return NULL;
+
+    if (strcmp(file, "langs") == 0) {
+        printf("\n");
+        printf("Languages dynamic library can be based on:\n\n");
+        printf("\tC\t\t\t\t[file.c ]\n");
+        printf("\tRust\t\t\t\t[file.rs]\n\n");
+        fflush(stdout);
+        return NULL;
+    }
+
+    if (new_script__init(s, file) < 0) {
+        printf("Error finding .so file\n");
+        return NULL;
+    }
+
+    if (new_script_open(s) < 0) {
+        printf("Error opening dynamic library\n");
+        return NULL;
+    }
+
+    return s;
+    
+}
+
+
+static int
+new_script__validate_data(struct perf_data *data)
+{
+    if (!data) {
+        printf("> no data\n");
+        return -1;
+    }
+    printf("> has data at %s \n", data->path);
+    fflush(stdout);
+
+    return 0;
+
+}
+
+
+static long
+process_file_header(int fd, struct new_script *s)
+{
+    struct perf_file_header fh;
+    u64 data[3];
+    void *ctx = NULL;
+    size_t e;
+
+    e = read(fd, &fh, sizeof(struct perf_file_header));
+    if (e != sizeof(struct perf_file_header)) {
+        if (fd == -1)
+            return -1;
+    }
+    
+    data[0] = fh.size;
+    data[1] = fh.data.size;
+    data[2] = fh.data.offset;
+    
+    if (fh.attr_size != sizeof(struct perf_file_attr)) {
+        printf("Error matching file attributes size\n");
+        return -1;
+    }
+    
+    if (s->process_file_header((void *)data, ctx) <  0)
+       return -1;
+
+    lseek(fd, fh.data.offset, SEEK_SET);
+
+    return fh.data.size;
+}
+
+
+static int
+process_event_header(struct perf_event_header *header, struct new_script *s)
+{
+    void *ctx = NULL;
+   
+    if (!header)
+        return -1;
+    
+    if (s->process_event_header((void *)header, ctx) <  0)
+       return -1;
+
+    return 0;
+}
+
+
+static void
+process_sample_mmap(void *buffer)
+{
+    struct perf_record_mmap mmap;
+    
+    memcpy(&mmap, buffer, sizeof(struct perf_record_mmap));
+    
+    printf("\tMMAP data: %u %llx %s\n", mmap.pid, mmap.start, mmap.filename);
+    fflush(stdout);
+
+}
+
+
+static void
+process_sample_data(void *buffer, size_t size)
+{
+    long count = size / sizeof(u64);
+ 
+    u64 *array = malloc(count * sizeof(u64));
+ 
+    memcpy(array, buffer + sizeof(struct perf_event_header), count * sizeof(u64));
+
+    printf("\tSample data: ");
+    for (int i = 0; i < count; i++) {
+        printf(" %lu", array[i]);
+    }
+    printf("\n");
+    fflush(stdout);
+}
+
+
+static int
+process_sample(struct perf_event_header *header, void *buffer)
+{
+    switch(header->type) {
+        case PERF_RECORD_MMAP:
+            process_sample_mmap(buffer);
+            break;
+        // case PERF_RECORD_COMM:
+        // case PERF_RECORD_FORK:
+        // case PERF_RECORD_EXIT:
+        case PERF_RECORD_SAMPLE:
+            process_sample_data(buffer, header->size - sizeof(*header));
+            break;
+        case PERF_RECORD_FINISHED_ROUND:
+            printf("\tEvent: PERF_RECORD_FINISHED_ROUND\n");
+            fflush(stdout);
+            break;
+        default:    // skip event
+            printf("\tSkipped event\n");
+            fflush(stdout);
+            break;
+    }
+    return 0;
+}
+    
+
+
+static int
+process_event_data(struct new_script *s, struct perf_event_header *header, void* buffer, size_t processed)
+{
+    void *ctx = NULL;
+    const size_t size = header->size; 
+
+    s->process_event_raw_data(buffer + processed, size, ctx);
+    
+    process_sample(header, buffer + processed);
+
+    return 0;
+}
+
+
+static int
+new_perf__process_all_data(struct perf_data *data, struct new_script *s)
+{
+    long data_size = 0;
+    long curr_size = 0;
+    size_t batch_size = 1024 * 1024;
+    char *buffer;
+    size_t processed = 0;
+    size_t event_size = 0;
+    
+    int fd = open(data->path, O_RDONLY);
+    if (fd == -1) {
+        printf("Error opening perf data file\n");
+        close(fd);
+        return -1;
+    }
+
+    
+    if ((data_size = process_file_header(fd, s)) < 0) {
+        printf("Error processing file header\n");
+        close(fd);
+        return -1;
+    }
+
+    buffer = malloc(batch_size);
+    if (!buffer) {
+        printf("Error allocating memory for file buffer\n");
+        close(fd);
+        return -1;
+    }
+
+    while (curr_size < data_size) {
+        size_t bytes_read = 0; 
+        
+        // final batch case
+        if ((curr_size + (long)batch_size) > data_size) {
+            batch_size = data_size - curr_size;
+        }
+
+        bytes_read = read(fd, buffer, batch_size);
+
+        processed = 0;
+        while (processed < bytes_read) {
+            struct perf_event_header *header;
+
+            if ((bytes_read - processed) >= sizeof(*header)) {
+                header = (struct perf_event_header *)(buffer + processed);
+            } else {
+                lseek(fd, -(bytes_read - processed), SEEK_CUR);
+                break;
+            }
+
+            event_size = header->size;
+
+            if ((processed + event_size) > bytes_read) { // split event case
+                lseek(fd, -(bytes_read - processed), SEEK_CUR);
+                break;
+            }
+            
+            if (process_event_header(header, s) < 0) {
+                close(fd);
+                return -1;
+            }
+
+            if (process_event_data(s, header, buffer, processed) < 0) {
+                printf("Error processing event data\n");
+                close(fd);
+                return -1;
+            }
+            
+            processed += event_size;
+            curr_size += event_size;
+        }
+    }
+    
+    close(fd);
+    return 0;
+}
+
+
+int
+new_script__start(struct new_script *s, struct perf_data *data)
+{
+    int ret;
+    void *d = NULL, *ctx = NULL;
+
+    if (!s)
+        goto out; 
+
+    if (new_script__validate_data(data) < 0)
+        goto out; 
+
+    printf("\n");
+    fflush(stdout);
+    
+    s->begin(d, ctx);
+   
+    ret = new_perf__process_all_data(data, s);
+    if (ret < 0) {
+        printf("Error processing data in new_script\n");
+        goto out;
+    }
+
+    s->end(d, ctx);
+
+    printf("\n");
+    fflush(stdout);
+    return 0;
+
+out:
+    return -1;
+}
+
+
+static int
+new_script__close(struct new_script *s)
+{
+	return dlclose(s->handle);
+}
+
+
+void
+new_script__cleanup(struct new_script *s)
+{
+    if (s)
+        new_script__close(s);
+    free(s);
+}
\ No newline at end of file
diff --git a/tools/perf/util/new_script.h b/tools/perf/util/new_script.h
new file mode 100644
index 000000000000..9dc4760b3a33
--- /dev/null
+++ b/tools/perf/util/new_script.h
@@ -0,0 +1,54 @@
+// Stefan Ene's code, under Intel - Linux Kernel Team
+/*
+ * new_script.h: header file for new scripting object allowing C and Rust event processing
+ *
+ */
+#ifndef __PERF_NEW_SCRIPT_H
+#define __PERF_NEW_SCRIPT_H
+
+
+struct new_script {
+	char		*file;
+    void        *handle;
+
+    void (*begin)(void *data, void *ctx);
+	void (*end)(void *data, void *ctx);
+
+    int (*process_file_header)(void *data, void *ctx);
+    int (*process_event_header)(void *data, void *ctx);
+    int (*process_event_raw_data)(void *data, const int size, void *ctx);
+
+};
+
+struct perf_event_header;
+
+struct perf_data;
+
+union perf_event;
+
+struct perf_file_section;
+
+struct perf_file_header;
+
+struct perf_event_attr;
+
+struct perf_file_attr {
+	struct perf_event_attr	    attr;
+	struct perf_file_section	ids;
+};
+
+
+struct perf_sample;
+
+struct ip_callchain;
+
+struct perf_record_mmap;
+
+struct new_script *new_script__new(const char *);
+
+void new_script__cleanup(struct new_script *);
+
+int new_script__start(struct new_script *, struct perf_data *);
+
+
+#endif /* __PERF_NEW_SCRIPT_H */
\ No newline at end of file
-- 
2.46.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ