dbus-glib-path: sketching data tracing sandbox/adrians/dbus-glib-path
authorAdrian Szyndela <adrian.s@samsung.com>
Fri, 25 Mar 2022 15:58:03 +0000 (16:58 +0100)
committerAdrian Szyndela <adrian.s@samsung.com>
Fri, 25 Mar 2022 15:58:03 +0000 (16:58 +0100)
Change-Id: Ic3130d69ede17fb8c5fc7585c9c1d3362320f4ea

tools/dbus-glib-path.c

index 62c7e40..542c977 100644 (file)
@@ -40,25 +40,6 @@ static void message_identifier_set(message_identifier_t *id, u32 serial, const c
        }
 }
 
-typedef struct {
-       u64                  timings[NUMBER_OF_STAGES];
-       void                *associated_buffer;
-       key_pointer_t        associated_received_message;
-       message_identifier_t message_identifier;
-} message_data_t;
-
-typedef struct {
-       union {
-               key_pointer_t        message_in_process;
-               message_identifier_t message_in_transit;
-       };
-} message_key_t;
-
-/* This hashmap contains mapping from a message identifier of some sort to
- * data associated with it, used for keeping timings and other identification means.
- * It is meant to track a message over its whole life time. */
-BPF_HASH(message_pointers, message_key_t, message_data_t);
-
 /* This hashmaps contain mapping from a message pointer to a timestamp.
  * It is meant to track a message within a single process. */
 BPF_HASH(stage1_timestamps, key_pointer_t, timestamp_value_t);
@@ -100,7 +81,7 @@ BPF_HISTOGRAM(timings_stage8);
 BPF_HISTOGRAM(timings_stage9);
 
 /*********** STAGE 1: creating a message ************/
-/* The stage starts with a g_dbus_message_new */
+/* The stage starts with a g_dbus_message_new_* */
 int stage1_begin(struct pt_regs  *ctx) {
        struct GDBusMessage *message = (struct GDBusMessage *)PT_REGS_RC(ctx);
        key_pointer_t key;
@@ -1008,3 +989,172 @@ int stage9_end(struct pt_regs *ctx, struct GDBusMessage *message) {
 
        return 0;
 }
+
+/*
+ * Message identification and associations through life time of a message:
+ * - on creation: pointer
+ * - on_worker_message_about_to_be_sent(): available serial+sender
+ * - write_message_async(): association of pointer with a buffer pointer
+ * - g_socket_send_message(): no more pointer, buffer pointer needed for filtering,
+ *                            still available serial+sender
+ *                            actually the pointer is still there, but not accessible in a direct way
+ * - dbus-daemon: only serial+sender
+ * - g_dbus_message_new_from_blob(): serial+sender, pointer on return
+ * - pointer available till the end
+ *
+ * So:
+ * pointer -> associate serial+sender -> buffer -> serial+sender -> pointer
+ * ( pointer                                     )
+ *           ( serial+sender             ------                   )........
+ *                                     ( buffer )
+ *                                                                  pointer
+ */
+
+typedef struct {
+       u64                  timings[NUMBER_OF_STAGES];
+       message_identifier_t message_identifier;
+} message_data_t;
+
+/* This hashmap contains mapping from a message identifier of some sort to
+ * data associated with it, used for keeping timings and other identification means.
+ * It is meant to track a message over its whole life time in the sending process. */
+BPF_HASH(sending_messages, key_pointer_t, message_data_t);
+BPF_HASH(transporting_messages, message_identifier_t, message_data_t);
+BPF_HASH(receiving_messages, key_pointer_t, message_data_t);
+/* Associations */
+BPF_HASH(buffer_to_pointer, key_pointer_t, key_pointer_t);
+
+/* Tracing starts with a g_dbus_message_new_* */
+int trace_message_begin(struct pt_regs  *ctx) {
+       struct GDBusMessage *message = (struct GDBusMessage *)PT_REGS_RC(ctx);
+       key_pointer_t key;
+       message_data_t msg_data = {0};
+
+       key_pointer_set_pointer(&key, message);
+
+       sending_messages.update(&key, &msg_data);
+
+       return 0;
+}
+
+/* A message pointer is either converted to something, or is freed */
+int trace_message_sending_cleanup(struct pt_regs *ctx, struct GDBusMessage *msg) {
+       key_pointer_t key;
+       key_pointer_set_pointer(&key, msg);
+       sending_messages.delete(&key);
+       /* The issue here is that the last stage is the same as the cleanup.
+        * So, how can we ensure that cleanup comes AFTER wrapping up the last stage?
+        * Does it have to be a single function?
+        * Are eBPF programs executed in a specific order, depending on the order of attaching them?
+        */
+//     receiving_messages.delete(&key);
+       return 0;
+}
+
+/* trace on_worker_message_about_to_be_sent() */
+int trace_on_worker_message_about_to_be_sent(struct pt_regs      *ctx,
+                                             struct GDBusMessage *message,
+                                             void                *user_data) {
+       GDBusConnection *connection = (GDBusConnection *)user_data;
+       key_pointer_t key;
+       message_data_t *msg_data;
+
+       if (connection == NULL)
+               return 0;
+
+       key_pointer_set_pointer(&key, message);
+       msg_data = sending_messages.lookup(&key);
+
+       if (msg_data == NULL)
+               return 0;
+
+       message_identifier_set(&msg_data->message_identifier,
+                              message->serial, (const char *)connection->bus_unique_name);
+
+       /* does it need to be updated in the map, or writing through the pointer is sufficient? */
+
+       return 0;
+}
+
+/* trace write_message_async() */
+int trace_write_message_async(struct pt_regs     *ctx,
+                              void               *worker,
+                              MessageToWriteData *data) {
+       key_pointer_t key;
+       key_pointer_t blob_pointer;
+       message_data_t *msg_data;
+
+       if (data == NULL)
+               return 0;
+
+       key_pointer_set_pointer(&key, (void *)data->message);
+       msg_data = sending_messages.lookup(&key);
+
+       if (msg_data == NULL)
+               return 0;
+
+       key_pointer_set_pointer(&blob_pointer, data->blob);
+       buffer_to_pointer.update(&blob_pointer, &key);
+
+       return 0;
+}
+
+/* trace g_socket_send_message */
+int trace_g_socket_send_message(struct pt_regs *ctx,
+                                void           *socket,
+                                void           *address,
+                                GOutputVector  *vector
+                                // don't care for more
+                                ) {
+       key_pointer_t *message_pointer;
+       key_pointer_t buffer_pointer;
+       message_data_t *msg_data;
+
+       if (vector == NULL)
+               return 0;
+
+       key_pointer_set_pointer(&buffer_pointer, (void *)vector->buffer);
+       message_pointer = buffer_to_pointer.lookup(&buffer_to_pointer);
+
+       if (message_pointer == NULL)
+               return 0;
+
+       msg_data = sending_messages.lookup(message_pointer);
+
+       if (msg_data == NULL)
+               return 0;
+
+       // convert from message pointer to serial+sender
+       transporting_messages.update(&msg_data->message_identifier, msg_data);
+
+       // cleanup here, or not yet?
+       sending_messages.delete(message_pointer);
+       buffer_to_pointer.delete(&buffer_to_pointer);
+
+       return 0;
+}
+
+/* TODO trace messages that end their life in dbus-daemon */
+
+/* trace return of g_dbus_message_new_from_blob() */
+int trace_g_dbus_message_new_from_blob(struct pt_regs *ctx,
+                                       uint8_t        *blob,
+                                       size_t          blob_len) {
+       struct GDBusMessage *message = (struct GDBusMessage *)PT_REGS_RC(ctx);
+       message_identifier_t msg_id;
+       message_data_t *msg_data;
+       key_pointer_t message_pointer;
+
+       if (msg_id_from_blob(blob, &msg_id) == NULL)
+               return 0;
+
+       msg_data = transporting_messages.lookup(&msg_id);
+       if (msg_data == NULL)
+               return 0;
+
+       key_pointer_set_pointer(&message_pointer, message);
+       receiving_messages.update(&message_pointer, msg_data);
+
+       return 0;
+}
+