}
}
-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);
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;
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;
+}
+