From 1bf95b7a4e31f9f26d828c1008687eb082727e15 Mon Sep 17 00:00:00 2001
From: Justus Winter <4winter@informatik.uni-hamburg.de>
Date: Fri, 23 May 2014 17:01:48 +0200
Subject: [PATCH hurd 2/9] libintrospection: a library for Hurd server
introspection
* Makefile (lib-subdirs): Add libintrospection.
* libintrospection/Makefile: New file.
* libintrospection/introspection.c: Likewise.
* libintrospection/introspection.h: Likewise.
* libintrospection/trace.c: Likewise.
---
Makefile | 2 +
libintrospection/Makefile | 27 +++++++
libintrospection/introspection.c | 86 ++++++++++++++++++++
libintrospection/introspection.h | 50 ++++++++++++
libintrospection/trace.c | 171 +++++++++++++++++++++++++++++++++++++++
5 files changed, 336 insertions(+)
create mode 100644 libintrospection/Makefile
create mode 100644 libintrospection/introspection.c
create mode 100644 libintrospection/introspection.h
create mode 100644 libintrospection/trace.c
diff --git a/Makefile b/Makefile
index 3178740..76eec21 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,8 @@ endif
# Other directories
other-subdirs = hurd doc config release include
+lib-subdirs += libintrospection
+
# All the subdirectories together
subdirs = $(lib-subdirs) $(prog-subdirs) $(other-subdirs)
diff --git a/libintrospection/Makefile b/libintrospection/Makefile
new file mode 100644
index 0000000..75adef2
--- /dev/null
+++ b/libintrospection/Makefile
@@ -0,0 +1,27 @@
+# Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2, or (at
+# your option) any later version.
+#
+# The GNU Hurd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the GNU Hurd. If not, see .
+
+dir := libintrospection
+makemode := library
+
+libname := libintrospection
+SRCS = introspection.c trace.c hurd_portUser.c
+installhdrs = introspection.h
+
+OBJS = $(SRCS:.c=.o)
+
+include ../Makeconf
diff --git a/libintrospection/introspection.c b/libintrospection/introspection.c
new file mode 100644
index 0000000..65c0727
--- /dev/null
+++ b/libintrospection/introspection.c
@@ -0,0 +1,86 @@
+/* Hurd server introspection.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see . */
+
+#include
+
+#include "introspection.h"
+#include "hurd_port_U.h"
+
+error_t
+introspection_set_port (mach_port_t task,
+ mach_port_t introspection_port)
+{
+ error_t err;
+ mach_port_t *ports;
+ size_t ports_len;
+
+ err = mach_ports_lookup (task, &ports, &ports_len);
+ if (err)
+ return err;
+
+ if (MACH_PORT_VALID (ports[HURD_PORT_REGISTER_INTROSPECTION]))
+ mach_port_deallocate (mach_task_self (),
+ ports[HURD_PORT_REGISTER_INTROSPECTION]);
+
+ ports[HURD_PORT_REGISTER_INTROSPECTION] = introspection_port;
+
+ err = mach_ports_register (task, ports, ports_len);
+ if (err)
+ {
+ size_t i;
+ for (i = 0; i < ports_len; i++)
+ if (MACH_PORT_VALID (ports[i]))
+ mach_port_deallocate (mach_task_self (), ports[i]);
+
+ return err;
+ }
+
+ return 0;
+}
+
+error_t
+introspection_get_port (mach_port_t task, mach_port_t *introspection_port)
+{
+ error_t err;
+ mach_port_t *ports;
+ size_t ports_len;
+
+ err = mach_ports_lookup (task, &ports, &ports_len);
+ if (! err)
+ {
+ size_t i;
+ if (MACH_PORT_VALID (*introspection_port))
+ mach_port_deallocate (mach_task_self (), *introspection_port);
+
+ for (i = 0; i < ports_len; i++)
+ if (i == HURD_PORT_REGISTER_INTROSPECTION)
+ *introspection_port = ports[i];
+ else
+ {
+ if (MACH_PORT_VALID (ports[i]))
+ mach_port_deallocate (mach_task_self (), ports[i]);
+ }
+ }
+ else
+ *introspection_port = MACH_PORT_DEAD;
+
+ return err;
+}
diff --git a/libintrospection/introspection.h b/libintrospection/introspection.h
new file mode 100644
index 0000000..ae9fcfa
--- /dev/null
+++ b/libintrospection/introspection.h
@@ -0,0 +1,50 @@
+/* Hurd server introspection.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see . */
+
+#ifndef _HURD_INTROSPECTION_H_
+#define _HURD_INTROSPECTION_H_
+
+#include
+#include
+
+error_t
+introspection_set_port (mach_port_t task,
+ mach_port_t introspection_port);
+
+error_t
+introspection_get_port (mach_port_t task,
+ mach_port_t *introspection_port);
+
+error_t
+introspection_trace_message (mach_port_t trace_port,
+ const mach_msg_header_t *msgp,
+ mach_port_t id);
+
+error_t
+introspection_trace_request (mach_port_t trace_port,
+ const mach_msg_header_t *msgp,
+ mach_port_t *id);
+
+error_t
+introspection_extract_message (mach_msg_header_t *msgp,
+ mach_port_t *id);
+
+#endif /* _HURD_INTROSPECTION_H_ */
diff --git a/libintrospection/trace.c b/libintrospection/trace.c
new file mode 100644
index 0000000..6654515
--- /dev/null
+++ b/libintrospection/trace.c
@@ -0,0 +1,171 @@
+/* Hurd server introspection.
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ Written by Justus Winter <4winter@informatik.uni-hamburg.de>
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see . */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "introspection.h"
+
+static const mach_msg_type_t ports_type = {
+ /* msgt_name = */ MACH_MSG_TYPE_PORT_NAME,
+ /* msgt_size = */ sizeof (mach_port_t) << 3,
+ /* msgt_number = */ 4,
+ /* msgt_inline = */ TRUE,
+ /* msgt_longform = */ FALSE,
+ /* msgt_deallocate = */ FALSE,
+ /* msgt_unused = */ 0
+};
+
+struct trace_footer
+{
+ mach_msg_type_t ports_type;
+ mach_port_t id;
+ mach_port_t bits;
+ mach_port_t remote_port;
+ mach_port_t local_port;
+};
+
+error_t
+introspection_trace_message (mach_port_t trace_port,
+ const mach_msg_header_t *msgp,
+ mach_port_t id)
+{
+ error_t err;
+ mach_msg_header_t *copyp;
+ void *msg_buf_ptr;
+ struct trace_footer *footer;
+ size_t size = msgp->msgh_size + sizeof *footer;
+
+ copyp = malloc (size);
+ if (copyp == NULL)
+ return ENOMEM;
+
+ memcpy (copyp, msgp, msgp->msgh_size);
+ footer = (void *) copyp + msgp->msgh_size;
+
+ /* Process the message data, clear msgt_deallocate and turn rights
+ into mere port names. */
+ msg_buf_ptr = (void *) copyp + sizeof *copyp;
+ while (msg_buf_ptr < (void *) copyp + msgp->msgh_size)
+ {
+ mach_msg_type_long_t *type_long = msg_buf_ptr;
+ mach_msg_type_t *type = &type_long->msgtl_header;
+ mach_msg_type_number_t nelt; /* Number of data items. */
+ mach_msg_type_size_t eltsize; /* Bytes per item. */
+
+ type->msgt_deallocate = 0;
+
+ if (! type->msgt_longform)
+ {
+ nelt = type->msgt_number;
+ eltsize = type->msgt_size / 8;
+ if (MACH_MSG_TYPE_PORT_ANY (type->msgt_name))
+ type->msgt_name = MACH_MSG_TYPE_PORT_NAME;
+ msg_buf_ptr += sizeof *type;
+ }
+ else
+ {
+ nelt = type_long->msgtl_number;
+ eltsize = type_long->msgtl_size / 8;
+ if (MACH_MSG_TYPE_PORT_ANY (type_long->msgtl_name))
+ type_long->msgtl_name = MACH_MSG_TYPE_PORT_NAME;
+ msg_buf_ptr += sizeof *type_long;
+ }
+
+ if (! type->msgt_inline)
+ /* This datum is out-of-line, meaning the message actually
+ contains a pointer to a vm_allocate'd region of data. */
+ msg_buf_ptr += sizeof (void *);
+ else
+ msg_buf_ptr += ((nelt * eltsize + sizeof(natural_t) - 1)
+ & ~(sizeof(natural_t) - 1));
+ }
+
+ copyp->msgh_bits =
+ MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0)
+ | (msgp->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+ copyp->msgh_remote_port = trace_port;
+ copyp->msgh_local_port = MACH_PORT_NULL;
+
+ *footer = (struct trace_footer)
+ {
+ ports_type,
+ id,
+ (mach_port_t) msgp->msgh_bits,
+ msgp->msgh_remote_port,
+ MACH_MSGH_BITS_LOCAL (msgp->msgh_bits)
+ == MACH_MSG_TYPE_PROTECTED_PAYLOAD
+ ? ports_payload_get_name (msgp->msgh_protected_payload)
+ : msgp->msgh_local_port,
+ };
+
+ err = mach_msg (copyp, MACH_SEND_MSG|MACH_SEND_TIMEOUT, size,
+ 0, MACH_PORT_NULL, 10 /* ms */, MACH_PORT_NULL);
+
+ free (copyp);
+ return err;
+}
+
+static mach_port_t
+make_id (void)
+{
+ static mach_port_t id;
+ mach_port_t result;
+
+ do
+ result = __atomic_add_fetch (&id, 1, __ATOMIC_RELAXED);
+ while (! MACH_PORT_VALID (result));
+
+ return result;
+}
+
+error_t
+introspection_trace_request (mach_port_t trace_port,
+ const mach_msg_header_t *msgp,
+ mach_port_t *id)
+{
+ *id = make_id ();
+ return introspection_trace_message (trace_port, msgp, *id);
+}
+
+error_t
+introspection_extract_message (mach_msg_header_t *msgp,
+ mach_port_t *id)
+{
+ size_t size = msgp->msgh_size - sizeof (struct trace_footer);
+ struct trace_footer *footer = (void *) msgp + size;
+
+ if (memcmp (&footer->ports_type, &ports_type, sizeof ports_type) != 0)
+ return MIG_BAD_ARGUMENTS;
+
+ msgp->msgh_bits =
+ ((mach_msg_bits_t) footer->bits & ~MACH_MSGH_BITS_PORTS_MASK)
+ || MACH_MSGH_BITS (MACH_MSG_TYPE_PORT_NAME, MACH_MSG_TYPE_PORT_NAME);
+ msgp->msgh_remote_port = footer->remote_port;
+ msgp->msgh_local_port = footer->local_port;
+ msgp->msgh_size = size;
+ *id = footer->id;
+ return 0;
+}
--
2.1.4