summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-09-24 18:24:04 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-09-24 18:24:04 +0200
commit0b7b919d1acce29637b5ae544ae6a73fafcde6df (patch)
treea8ed6010fc334b60c5dc9cc8344f1f240b18421e /debian
parent82fe83952f061ff0c8cacfaa1eab63592ad9f435 (diff)
add patch series
Diffstat (limited to 'debian')
-rw-r--r--debian/patches/introspection0001-hurd-add-an-Hurd-server-introspection-protocol.patch147
-rw-r--r--debian/patches/introspection0002-libintrospection-a-library-for-Hurd-server-introspec.patch401
-rw-r--r--debian/patches/introspection0003-libports-implement-the-Hurd-server-introspection-pro.patch481
-rw-r--r--debian/patches/introspection0004-utils-implement-portinfo-query-process.patch168
-rw-r--r--debian/patches/introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch107
-rw-r--r--debian/patches/introspection0006-libpager-annotate-objects-managed-by-libports.patch61
-rw-r--r--debian/patches/introspection0007-ext2fs-annotate-objects-managed-by-libports.patch99
-rw-r--r--debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch373
-rw-r--r--debian/patches/introspection0009-fixup_libports.patch122
-rw-r--r--debian/patches/series9
10 files changed, 1968 insertions, 0 deletions
diff --git a/debian/patches/introspection0001-hurd-add-an-Hurd-server-introspection-protocol.patch b/debian/patches/introspection0001-hurd-add-an-Hurd-server-introspection-protocol.patch
new file mode 100644
index 00000000..6ffa437e
--- /dev/null
+++ b/debian/patches/introspection0001-hurd-add-an-Hurd-server-introspection-protocol.patch
@@ -0,0 +1,147 @@
+From 1d2622b5bb6a49f0165bfdc10278451a9228c18e Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 16:40:12 +0200
+Subject: [PATCH hurd 1/9] hurd: add an Hurd server introspection protocol
+
+Most Hurd servers use libports to manage receive rights and the
+associated objects. These procedures can be used to query the state
+associated with receive rights managed by libports.
+
+The procedures are not specific to libports. Any Hurd server can
+implement this protocol. To do so, a server installs a send right in
+the array of well-known ports, under the key
+HURD_PORT_REGISTER_INTROSPECTION.
+
+* hurd/hurd_port.defs: New file.
+* hurd/hurd_types.h (HURD_PORT_REGISTER_INTROSPECTION): New macro.
+(HURD_PORT_REGISTER_MAX): Likewise.
+* hurd/subsystems: Add hurd_port subsystem.
+---
+ hurd/hurd_port.defs | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ hurd/hurd_types.h | 7 +++++
+ hurd/subsystems | 1 +
+ 3 files changed, 86 insertions(+)
+ create mode 100644 hurd/hurd_port.defs
+
+diff --git a/hurd/hurd_port.defs b/hurd/hurd_port.defs
+new file mode 100644
+index 0000000..d1f46b3
+--- /dev/null
++++ b/hurd/hurd_port.defs
+@@ -0,0 +1,78 @@
++/* Hurd server introspection.
++
++ 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 <http://www.gnu.org/licenses/>. */
++
++subsystem hurd_port 39000;
++
++/* Hurd server introspection.
++
++ Most Hurd servers use libports to manage receive rights and the
++ associated objects. These procedures can be used to query the
++ state associated with receive rights managed by libports.
++
++ The procedures are not specific to libports. Any Hurd server can
++ implement this protocol. To do so, a server installs a send right
++ in the array of well-known ports, under the key
++ HURD_PORT_REGISTER_INTROSPECTION.
++
++ A client in possession of the servers task port can retrieve a copy
++ of this send right using mach_ports_lookup. */
++
++#include <hurd/hurd_types.defs>
++
++#ifdef HURD_PORT_IMPORTS
++HURD_PORT_IMPORTS
++#endif
++
++INTR_INTERFACE
++
++/* Return the number of hard and weak references of the object
++ directly associated with the receive right NAME.
++
++ Return EINVAL if NAME does not denote a receive right managed by
++ the port-to-object mapper, or if the concept of reference counting
++ simply does not apply. */
++routine hurd_port_get_refcounts (
++ introspection: mach_port_t;
++ name: mach_port_name_t;
++ waittime timeout: natural_t;
++ RPT
++ out hard: natural_t;
++ out weak: natural_t);
++
++/* Return a compact, human-readable description of the object related
++ with the receive right NAME.
++
++ This description is meant for debugging purposes and should include
++ relevant internal state. If possible, it should include
++ information that is meaningful in other contexts (like a file name,
++ or the inode number).
++
++ Return EINVAL if NAME does not denote a receive right managed by
++ the port-to-object mapper. */
++routine hurd_port_debug_info (
++ introspection: mach_port_t;
++ name: mach_port_name_t;
++ waittime timeout: natural_t;
++ RPT
++ out debug_info: string_t);
++
++routine hurd_port_trace_class_rpcs (
++ introspection: mach_port_t;
++ name: mach_port_name_t;
++ trace_port: mach_port_send_t);
+diff --git a/hurd/hurd_types.h b/hurd/hurd_types.h
+index 4341177..76a8201 100644
+--- a/hurd/hurd_types.h
++++ b/hurd/hurd_types.h
+@@ -23,6 +23,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ #include <time.h> /* For struct timespec. */
+ #include <mach/std_types.h> /* For mach_port_t et al. */
+ #include <mach/message.h> /* For mach_msg_id_t et al. */
++#include <mach/mach_param.h> /* For TASK_PORT_REGISTER_MAX. */
+ #include <sys/types.h> /* For pid_t and uid_t. */
+
+ /* A string identifying this release of the GNU Hurd. Our
+@@ -372,4 +373,10 @@ enum
+ INIT_INT_MAX,
+ };
+
++/* Define the well-known ports available via mach_ports_lookup. */
++#define HURD_PORT_REGISTER_INTROSPECTION 0
++
++/* This is a fixed limit. */
++#define HURD_PORT_REGISTER_MAX TASK_PORT_REGISTER_MAX
++
+ #endif
+diff --git a/hurd/subsystems b/hurd/subsystems
+index c05895c..59893b2 100644
+--- a/hurd/subsystems
++++ b/hurd/subsystems
+@@ -36,6 +36,7 @@ tape 35000 Special control operations for magtapes
+ login 36000 Database of logged-in users
+ pfinet 37000 Internet configuration calls
+ password 38000 Password checker
++hurd_port 39000 Port debugging and introspection
+ <ioctl space> 100000- First subsystem of ioctl class 'f' (lowest class)
+ tioctl 156000 Ioctl class 't' (terminals)
+ tioctl 156200 (continued)
+--
+2.1.4
+
diff --git a/debian/patches/introspection0002-libintrospection-a-library-for-Hurd-server-introspec.patch b/debian/patches/introspection0002-libintrospection-a-library-for-Hurd-server-introspec.patch
new file mode 100644
index 00000000..55d691f5
--- /dev/null
+++ b/debian/patches/introspection0002-libintrospection-a-library-for-Hurd-server-introspec.patch
@@ -0,0 +1,401 @@
+From 9917c46bf101ab34c26a098936cdd0b3acd3f45d 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 | 175 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 340 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 <http://www.gnu.org/licenses/>.
++
++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 <http://www.gnu.org/licenses/>. */
++
++#include <mach.h>
++
++#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 <http://www.gnu.org/licenses/>. */
++
++#ifndef _HURD_INTROSPECTION_H_
++#define _HURD_INTROSPECTION_H_
++
++#include <errno.h>
++#include <mach.h>
++
++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..ac2fdb0
+--- /dev/null
++++ b/libintrospection/trace.c
+@@ -0,0 +1,175 @@
++/* 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 <http://www.gnu.org/licenses/>. */
++
++#include <error.h>
++#include <hurd/ports.h>
++#include <mach/mig_errors.h>
++#include <pthread.h>
++#include <stdlib.h>
++#include <string.h>
++
++#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_MSG_OPTION_NONE, size,
++ 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++
++ free (copyp);
++ return err;
++}
++
++static mach_port_t
++make_id (void)
++{
++ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
++ static mach_port_t id;
++ mach_port_t result;
++
++ pthread_mutex_lock (&lock);
++
++ do
++ id += 1;
++ while (! MACH_PORT_VALID (id));
++
++ result = id;
++ pthread_mutex_unlock (&lock);
++
++ 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;
++ 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
+
diff --git a/debian/patches/introspection0003-libports-implement-the-Hurd-server-introspection-pro.patch b/debian/patches/introspection0003-libports-implement-the-Hurd-server-introspection-pro.patch
new file mode 100644
index 00000000..1f5393d0
--- /dev/null
+++ b/debian/patches/introspection0003-libports-implement-the-Hurd-server-introspection-pro.patch
@@ -0,0 +1,481 @@
+From 798eae80f9de731d0dc3ff5bb8172cef99cad207 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 16:47:14 +0200
+Subject: [PATCH hurd 3/9] libports: implement the Hurd server introspection
+ protocol
+
+Add a compact and self-contained introspection server to libports.
+Add functions to to label port buckets and classes. Make it possible
+to provide a function that given an object of a class, returns a
+human-readable representation for it.
+
+* libports/introspection.c: New file.
+* libports/create-bucket.c (ports_label_bucket): New function.
+* libports/create-class.c (ports_set_debug_info): Likewise.
+* libports/manage-multithread.c (internal_demuxer): Trace messages if
+desired.
+* libports/manage-one-thread.c (internal_demuxer): Likewise.
+* libports/ports.h (struct port_bucket): Add label.
+(struct port_class): Add debug_info and label.
+(ports_label_bucket): New declaration.
+(ports_set_debug_info): Likewise.
+* libports/Makefile (SRCS): Add introspection.c.
+(OBJS): Add hurd_portServer.o.
+---
+ ext2fs/Makefile | 3 +-
+ fatfs/Makefile | 3 +-
+ isofs/Makefile | 3 +-
+ libports/Makefile | 6 +-
+ libports/create-bucket.c | 7 ++
+ libports/create-class.c | 16 ++++
+ libports/introspection.c | 189 ++++++++++++++++++++++++++++++++++++++++++
+ libports/manage-multithread.c | 10 +++
+ libports/manage-one-thread.c | 11 +++
+ libports/ports.h | 14 ++++
+ tmpfs/Makefile | 3 +-
+ 11 files changed, 258 insertions(+), 7 deletions(-)
+ create mode 100644 libports/introspection.c
+
+diff --git a/ext2fs/Makefile b/ext2fs/Makefile
+index 8d2e68c..9d72fda 100644
+--- a/ext2fs/Makefile
++++ b/ext2fs/Makefile
+@@ -23,7 +23,8 @@ target = ext2fs
+ SRCS = balloc.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
+ inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c
+ OBJS = $(SRCS:.c=.o)
+-HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
++HURDLIBS = diskfs pager iohelp fshelp store ports ihash introspection \
++ shouldbeinlibc
+ OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
+
+ include ../Makeconf
+diff --git a/fatfs/Makefile b/fatfs/Makefile
+index 6224b64..e4f01ec 100644
+--- a/fatfs/Makefile
++++ b/fatfs/Makefile
+@@ -22,7 +22,8 @@ target = fatfs
+ SRCS = inode.c main.c dir.c pager.c fat.c virt-inode.c node-create.c
+
+ OBJS = $(SRCS:.c=.o)
+-HURDLIBS = diskfs iohelp fshelp store pager ports ihash shouldbeinlibc
++HURDLIBS = diskfs iohelp fshelp store pager ports ihash introspection \
++ shouldbeinlibc
+ OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
+
+ include ../Makeconf
+diff --git a/isofs/Makefile b/isofs/Makefile
+index 6475c52..9e399bf 100644
+--- a/isofs/Makefile
++++ b/isofs/Makefile
+@@ -21,7 +21,8 @@ target = iso9660fs
+ SRCS = inode.c main.c lookup.c pager.c rr.c
+
+ OBJS = $(SRCS:.c=.o)
+-HURDLIBS = diskfs iohelp fshelp store pager ports ihash shouldbeinlibc
++HURDLIBS = diskfs iohelp fshelp store pager ports ihash introspection \
++ shouldbeinlibc
+ OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
+
+ include ../Makeconf
+diff --git a/libports/Makefile b/libports/Makefile
+index af881f8..ec98bad 100644
+--- a/libports/Makefile
++++ b/libports/Makefile
+@@ -36,13 +36,13 @@ SRCS = create-bucket.c create-class.c \
+ interrupt-operation.c interrupt-on-notify.c interrupt-notified-rpcs.c \
+ dead-name.c create-port.c import-port.c default-uninhibitable-rpcs.c \
+ claim-right.c transfer-right.c create-port-noinstall.c create-internal.c \
+- interrupted.c extern-inline.c port-deref-deferred.c
++ interrupted.c extern-inline.c port-deref-deferred.c introspection.c
+
+ installhdrs = ports.h port-deref-deferred.h
+
+-HURDLIBS= ihash
++HURDLIBS= ihash introspection
+ LDLIBS += -lpthread
+-OBJS = $(SRCS:.c=.o) notifyServer.o interruptServer.o
++OBJS = $(SRCS:.c=.o) notifyServer.o interruptServer.o hurd_portServer.o
+
+ MIGCOMSFLAGS = -prefix ports_
+ MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+diff --git a/libports/create-bucket.c b/libports/create-bucket.c
+index 82c00a4..34559f5 100644
+--- a/libports/create-bucket.c
++++ b/libports/create-bucket.c
+@@ -49,5 +49,12 @@ ports_create_bucket ()
+ hurd_ihash_init (&ret->htable, offsetof (struct port_info, hentry));
+ ret->rpcs = ret->flags = ret->count = 0;
+ _ports_threadpool_init (&ret->threadpool);
++ ret->label = "unlabeled bucket";
+ return ret;
+ }
++
++/* Label BUCKET with LABEL. */
++void ports_label_bucket (struct port_bucket *bucket, const char *label)
++{
++ bucket->label = label;
++}
+diff --git a/libports/create-class.c b/libports/create-class.c
+index 782f52b..8abf643 100644
+--- a/libports/create-class.c
++++ b/libports/create-class.c
+@@ -41,6 +41,22 @@ ports_create_class (void (*clean_routine)(void *),
+ cl->rpcs = 0;
+ cl->count = 0;
+ cl->uninhibitable_rpcs = ports_default_uninhibitable_rpcs;
++ cl->debug_info = NULL;
++ cl->label = "unlabeled class";
++ cl->trace_port = MACH_PORT_NULL;
+
+ return cl;
+ }
++
++/* Label CLASS with LABEL. Use DEBUG_INFO to format human-readable
++ information about a given object belonging to CLASS into an buffer,
++ or the default formatting function if DEBUG_INFO is NULL. */
++void
++ports_label_class (struct port_class *class,
++ const char *label,
++ error_t (*debug_info) (const void *, char *, size_t))
++{
++ class->label = label;
++ if (debug_info)
++ class->debug_info = debug_info;
++}
+diff --git a/libports/introspection.c b/libports/introspection.c
+new file mode 100644
+index 0000000..912c768
+--- /dev/null
++++ b/libports/introspection.c
+@@ -0,0 +1,189 @@
++/* Hurd server introspection.
++
++ 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 <http://www.gnu.org/licenses/>. */
++
++#include <error.h>
++#include <hurd/introspection.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <string.h>
++
++#include "ports.h"
++#include "hurd_port_U.h"
++
++/* We service introspection requests on this port. */
++static mach_port_t introspection_port;
++
++/* We use a separate thread to service the introspection requests. It
++ is a straight forward Mach server for the hurd_port protocol. */
++static void *
++service_introspection_requests (void *arg)
++{
++ error_t err;
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
++ &introspection_port);
++ if (err)
++ {
++ error (0, err, "mach_port_allocate");
++ return NULL;
++ }
++
++ err = mach_port_insert_right (mach_task_self (),
++ introspection_port, introspection_port,
++ MACH_MSG_TYPE_MAKE_SEND);
++ if (err)
++ {
++ error (0, err, "mach_port_insert_right");
++ return NULL;
++ }
++
++ err = introspection_set_port (mach_task_self (), introspection_port);
++ if (err)
++ {
++ error (0, err, "introspection_set_port");
++ return NULL;
++ }
++
++ /* XXX mig should emit this declaration. */
++ boolean_t ports_hurd_port_server (mach_msg_header_t *InHeadP,
++ mach_msg_header_t *OutHeadP);
++
++ while (1)
++ mach_msg_server (ports_hurd_port_server, 0, introspection_port);
++
++ /* Not reached. */
++ return NULL;
++}
++
++/* Start the introspection server before main is called. */
++static void __attribute__ ((constructor))
++init (void)
++{
++ error_t err;
++
++ pthread_t thread;
++ pthread_attr_t attr;
++#define STACK_SIZE (64 * 1024)
++ pthread_attr_init (&attr);
++ pthread_attr_setstacksize (&attr, STACK_SIZE);
++#undef STACK_SIZE
++
++ err = pthread_create (&thread, &attr,
++ service_introspection_requests, NULL);
++ if (err)
++ error (1, err, "pthread_create");
++ pthread_detach (thread);
++}
++
++/* Return the number of hard and weak references of the object
++ directly associated with the receive right NAME.
++
++ Return EINVAL if NAME does not denote a receive right managed by
++ the port-to-object mapper, or if the concept of reference counting
++ simply does not apply. */
++error_t
++ports_S_hurd_port_get_refcounts (mach_port_t port,
++ mach_port_t name,
++ natural_t *hard,
++ natural_t *weak)
++{
++ struct references result;
++ struct port_info *pi;
++
++ if (port != introspection_port)
++ return EOPNOTSUPP;
++
++ pi = ports_lookup_port (0, name, 0);
++ if (pi == NULL)
++ return EINVAL;
++
++ refcounts_references (&pi->refcounts, &result);
++
++ *hard = result.hard - 1;
++ *weak = result.weak;
++ ports_port_deref (pi);
++ return 0;
++}
++
++static error_t
++default_debug_info (const void *port, char *buffer, size_t size)
++{
++ const struct port_info *pi = port;
++ snprintf (buffer, size,
++ "bucket: %s, class: %s",
++ pi->bucket->label, pi->class->label);
++ return 0;
++}
++
++/* Return a compact, human-readable description of the object related
++ with the receive right NAME.
++
++ This description is meant for debugging purposes and should include
++ relevant internal state. If possible, it should include
++ information that is meaningful in other contexts (like a file name,
++ or the inode number).
++
++ Return EINVAL if NAME does not denote a receive right managed by
++ the port-to-object mapper. */
++error_t
++ports_S_hurd_port_debug_info (mach_port_t port,
++ mach_port_t name,
++ char *info)
++{
++ error_t err;
++ struct port_info *pi;
++
++ if (port != introspection_port)
++ return EOPNOTSUPP;
++
++ pi = ports_lookup_port (0, name, 0);
++ if (pi == NULL)
++ return EINVAL;
++
++ if (pi->class->debug_info)
++ err = pi->class->debug_info (pi, info, 1024 /* XXX */);
++ else
++ err = default_debug_info (pi, info, 1024 /* XXX */);
++ info[1023 /* XXX */] = 0;
++
++ ports_port_deref (pi);
++ return err;
++}
++
++error_t
++ports_S_hurd_port_trace_class_rpcs (mach_port_t port,
++ mach_port_t name,
++ mach_port_t trace_port)
++{
++ struct port_info *pi;
++
++ if (port != introspection_port)
++ return EOPNOTSUPP;
++
++ pi = ports_lookup_port (0, name, 0);
++ if (pi == NULL)
++ return EINVAL;
++
++ if (MACH_PORT_VALID (pi->class->trace_port))
++ mach_port_deallocate (mach_task_self (), pi->class->trace_port);
++
++ pi->class->trace_port = trace_port;
++ ports_port_deref (pi);
++ return 0;
++}
+diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
+index 60743d9..8707d98 100644
+--- a/libports/manage-multithread.c
++++ b/libports/manage-multithread.c
+@@ -21,6 +21,7 @@
+ #include "ports.h"
+ #include <assert.h>
+ #include <error.h>
++#include <hurd/introspection.h>
+ #include <stdio.h>
+ #include <mach/message.h>
+ #include <mach/thread_info.h>
+@@ -189,6 +190,11 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
+
+ if (pi)
+ {
++ mach_port_t trace_port = pi->class->trace_port;
++ mach_port_t trace_id;
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
++ introspection_trace_request (trace_port, inp, &trace_id);
++
+ error_t err = ports_begin_rpc (pi, inp->msgh_id, &link);
+ if (err)
+ {
+@@ -207,6 +213,10 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
+ ports_end_rpc (pi, &link);
+ }
+ ports_port_deref (pi);
++
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
++ && outp->RetCode != MIG_NO_REPLY)
++ introspection_trace_message (trace_port, outp, trace_id);
+ }
+ else
+ {
+diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c
+index b920338..55aa378 100644
+--- a/libports/manage-one-thread.c
++++ b/libports/manage-one-thread.c
+@@ -18,6 +18,8 @@
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
++#include <hurd/introspection.h>
++
+ #include "ports.h"
+
+ void
+@@ -80,6 +82,11 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
+
+ if (pi)
+ {
++ mach_port_t trace_port = pi->class->trace_port;
++ mach_port_t trace_id;
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
++ introspection_trace_request (trace_port, inp, &trace_id);
++
+ err = ports_begin_rpc (pi, inp->msgh_id, &link);
+ if (err)
+ {
+@@ -96,6 +103,10 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
+ ports_end_rpc (pi, &link);
+ }
+ ports_port_deref (pi);
++
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
++ && outp->RetCode != MIG_NO_REPLY)
++ introspection_trace_message (trace_port, outp, trace_id);
+ }
+ else
+ {
+diff --git a/libports/ports.h b/libports/ports.h
+index 9299bc4..a31b894 100644
+--- a/libports/ports.h
++++ b/libports/ports.h
+@@ -76,6 +76,7 @@ struct port_bucket
+ int flags;
+ int count;
+ struct ports_threadpool threadpool;
++ const char *label;
+ };
+ /* FLAGS above are the following: */
+ #define PORT_BUCKET_INHIBITED PORTS_INHIBITED
+@@ -91,7 +92,10 @@ struct port_class
+ int count;
+ void (*clean_routine) (void *);
+ void (*dropweak_routine) (void *);
++ error_t (*debug_info) (const void *, char *, size_t);
+ struct ports_msg_id_range *uninhibitable_rpcs;
++ const char *label;
++ mach_port_t trace_port;
+ };
+ /* FLAGS are the following: */
+ #define PORT_CLASS_INHIBITED PORTS_INHIBITED
+@@ -160,6 +164,9 @@ extern struct ports_msg_id_range *ports_default_uninhibitable_rpcs;
+ /* Create and return a new bucket. */
+ struct port_bucket *ports_create_bucket (void);
+
++/* Label BUCKET with LABEL. */
++void ports_label_bucket (struct port_bucket *bucket, const char *label);
++
+ /* Create and return a new port class. If nonzero, CLEAN_ROUTINE will
+ be called for each allocated port object in this class when it is
+ being destroyed. If nonzero, DROPWEAK_ROUTINE will be called
+@@ -169,6 +176,12 @@ struct port_bucket *ports_create_bucket (void);
+ struct port_class *ports_create_class (void (*clean_routine)(void *),
+ void (*dropweak_routine)(void *));
+
++/* Label CLASS with LABEL. Use DEBUG_INFO to format human-readable
++ information about a given object belonging to CLASS into an buffer,
++ or the default formatting function if DEBUG_INFO is NULL. */
++void ports_label_class (struct port_class *class, const char *label,
++ error_t (*debug_info) (const void *, char *, size_t));
++
+ /* Create and return in RESULT a new port in CLASS and BUCKET; SIZE bytes
+ will be allocated to hold the port structure and whatever private data the
+ user desires. */
+@@ -482,5 +495,6 @@ extern int _ports_flags;
+ void _ports_complete_deallocate (struct port_info *);
+ error_t _ports_create_port_internal (struct port_class *, struct port_bucket *,
+ size_t, void *, int);
++error_t _ports_trace_message (mach_port_t, const mach_msg_header_t *);
+
+ #endif
+diff --git a/tmpfs/Makefile b/tmpfs/Makefile
+index fdcae34..fc27909 100644
+--- a/tmpfs/Makefile
++++ b/tmpfs/Makefile
+@@ -23,7 +23,8 @@ target = tmpfs
+ SRCS = tmpfs.c node.c dir.c pager-stubs.c
+ OBJS = $(SRCS:.c=.o) default_pagerUser.o
+ # XXX The shared libdiskfs requires libstore even though we don't use it here.
+-HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
++HURDLIBS = diskfs pager iohelp fshelp store ports ihash introspection \
++ shouldbeinlibc
+ OTHERLIBS = -lpthread
+
+ include ../Makeconf
+--
+2.1.4
+
diff --git a/debian/patches/introspection0004-utils-implement-portinfo-query-process.patch b/debian/patches/introspection0004-utils-implement-portinfo-query-process.patch
new file mode 100644
index 00000000..dfd095e9
--- /dev/null
+++ b/debian/patches/introspection0004-utils-implement-portinfo-query-process.patch
@@ -0,0 +1,168 @@
+From 6c2d3e9e3f4b30b3cea7df49db75272554a88c29 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 17:38:46 +0200
+Subject: [PATCH hurd 4/9] utils: implement portinfo --query-process
+
+Implement portinfo --query-process (hopefully) as envisaged by a
+comment in portinfo.c. We use the new Hurd server introspection
+protocol to obtain information about the objects related to ports:
+
+% utils/portinfo --receive --query-process 5586 77
+ 77: receive [bucket: diskfs_port_bucket, class: diskfs_protid_class,
+ node{inode: 48194, hard: 1, weak: 1},
+ path: hello/hurd/developers_:)]
+
+* libshouldbeinlibc/Makefile (OBJS): Add hurd_portUser.o.
+* libshouldbeinlibc/portinfo.c (show_portinfo_query): New function.
+(print_port_info): Use show_portinfo_query if desired.
+* libshouldbeinlibc/portinfo.h (PORTINFO_QUERY): New macro.
+* utils/portinfo.c (argp_option): Drop #if 0.
+(parse_opt): Handle --query-process.
+---
+ libshouldbeinlibc/Makefile | 2 +-
+ libshouldbeinlibc/portinfo.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
+ libshouldbeinlibc/portinfo.h | 1 +
+ utils/portinfo.c | 3 +-
+ 4 files changed, 72 insertions(+), 3 deletions(-)
+
+diff --git a/libshouldbeinlibc/Makefile b/libshouldbeinlibc/Makefile
+index 633d60e..a41a879 100644
+--- a/libshouldbeinlibc/Makefile
++++ b/libshouldbeinlibc/Makefile
+@@ -36,6 +36,6 @@ installhdrs = idvec.h timefmt.h maptime.h \
+
+ installhdrsubdir = .
+
+-OBJS = $(SRCS:.c=.o)
++OBJS = $(SRCS:.c=.o) hurd_portUser.o
+
+ include ../Makeconf
+diff --git a/libshouldbeinlibc/portinfo.c b/libshouldbeinlibc/portinfo.c
+index e6305c6..f99b789 100644
+--- a/libshouldbeinlibc/portinfo.c
++++ b/libshouldbeinlibc/portinfo.c
+@@ -17,10 +17,77 @@
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
++#include <assert.h>
++#include <error.h>
++#include <string.h>
+ #include <sys/types.h>
+ #include <sys/mman.h>
+
+ #include "portinfo.h"
++#include "hurd_port_U.h"
++
++static void
++show_portinfo_query (mach_port_t task, mach_port_t name,
++ unsigned show, FILE *stream)
++{
++ error_t err;
++ static mach_port_t introspection_port;
++ static mach_port_t for_task;
++
++ if (task != for_task)
++ {
++ 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;
++
++ for_task = task;
++ }
++
++ if (! MACH_PORT_VALID (introspection_port))
++ return;
++
++ string_t info; /* XXX */
++ err = hurd_port_debug_info (introspection_port, name, 100, info);
++ if (err)
++ {
++ if (err != EINVAL)
++ error (0, err, "hurd_port_debug_info");
++ return;
++ }
++
++ if (strlen (info) > 0)
++ fprintf (stream, " [%s", info);
++
++ if (show & PORTINFO_DETAILS)
++ {
++ unsigned int hard, weak;
++ err = hurd_port_get_refcounts (introspection_port, name, 100,
++ &hard, &weak);
++ if (! err)
++ fprintf (stream, ", hard: %u, weak: %u", hard, weak);
++ }
++
++ fprintf (stream, "]");
++}
++
+
+ /* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+@@ -83,6 +150,8 @@ print_port_info (mach_port_t name, mach_port_type_t type, task_t task,
+ status.mps_nsrequest ? ", ns-req" : "");
+ }
+ }
++ if (show & PORTINFO_QUERY)
++ show_portinfo_query (task, name, show, stream);
+ }
+ if (type & MACH_PORT_TYPE_SEND)
+ {
+diff --git a/libshouldbeinlibc/portinfo.h b/libshouldbeinlibc/portinfo.h
+index 143c289..bd96eb8 100644
+--- a/libshouldbeinlibc/portinfo.h
++++ b/libshouldbeinlibc/portinfo.h
+@@ -31,6 +31,7 @@
+ #define PORTINFO_DETAILS 0x1
+ #define PORTINFO_MEMBERS 0x4
+ #define PORTINFO_HEX_NAMES 0x8
++#define PORTINFO_QUERY 0x10
+
+ /* Prints info about NAME in TASK to STREAM, in a way described by the flags
+ in SHOW. If TYPE is non-zero, it should be what mach_port_type returns
+diff --git a/utils/portinfo.c b/utils/portinfo.c
+index 4c40352..27998db 100644
+--- a/utils/portinfo.c
++++ b/utils/portinfo.c
+@@ -44,10 +44,8 @@ static const struct argp_option options[] = {
+ {"verbose", 'v', 0, 0, "Give more detailed information"},
+ {"members", 'm', 0, 0, "Show members of port-sets"},
+ {"hex-names", 'x', 0, 0, "Show port names in hexadecimal"},
+-#if 0 /* XXX implement this */
+ {"query-process", 'q', 0, 0, "Query the process itself for the identity of"
+ " the ports in question -- requires the process be in a sane state"},
+-#endif
+ {"hold", '*', 0, OPTION_HIDDEN},
+
+ {0,0,0,0, "Selecting which names to show:", 2},
+@@ -249,6 +247,7 @@ main (int argc, char **argv)
+ case 'v': show |= PORTINFO_DETAILS; break;
+ case 'm': show |= PORTINFO_MEMBERS; break;
+ case 'x': show |= PORTINFO_HEX_NAMES; break;
++ case 'q': show |= PORTINFO_QUERY; break;
+
+ case 'r': only |= MACH_PORT_TYPE_RECEIVE; break;
+ case 's': only |= MACH_PORT_TYPE_SEND; break;
+--
+2.1.4
+
diff --git a/debian/patches/introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch b/debian/patches/introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch
new file mode 100644
index 00000000..4c8c543e
--- /dev/null
+++ b/debian/patches/introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch
@@ -0,0 +1,107 @@
+From d3f069f39fae7a622e257e919ecfa8dd9c5a78d5 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 18:17:33 +0200
+Subject: [PATCH hurd 5/9] libdiskfs: annotate objects managed by libports
+
+Label all port classes and diskfs_port_bucket. Provide
+diskfs_format_debug_info which prints a human-readable description of
+a protid object, which notably includes the path and the inode number.
+
+* libdiskfs/diskfs.h (diskfs_format_debug_info): New declaration.
+* libdiskfs/init-init.c (diskfs_format_debug_info): New function.
+(diskfs_init_diskfs): Add annotations to classes and bucket.
+---
+ libdiskfs/diskfs.h | 8 ++++++++
+ libdiskfs/init-init.c | 41 ++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 44 insertions(+), 5 deletions(-)
+
+diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
+index 11fb0ad..c2f97ad 100644
+--- a/libdiskfs/diskfs.h
++++ b/libdiskfs/diskfs.h
+@@ -591,6 +591,14 @@ error_t (*diskfs_read_symlink_hook)(struct node *np, char *target);
+ default function always returns EOPNOTSUPP. */
+ error_t diskfs_get_source (struct protid *cred,
+ char *source, size_t source_len);
++
++/* The user may define this function. The function must provide a
++ human-readable description of PROTID in BUFFER of size SIZE. The
++ default implementation generates a reasonable amount of
++ information. */
++error_t diskfs_format_debug_info (const void *protid,
++ char *buffer, size_t size);
++
+
+ /* Libdiskfs contains a node cache.
+
+diff --git a/libdiskfs/init-init.c b/libdiskfs/init-init.c
+index 357960b..07714f0 100644
+--- a/libdiskfs/init-init.c
++++ b/libdiskfs/init-init.c
+@@ -24,6 +24,7 @@
+ #include <hurd/fsys.h>
+ #include <stdio.h>
+ #include <maptime.h>
++#include <inttypes.h>
+
+ /* For safe inlining of diskfs_node_disknode and
+ diskfs_disknode_node. */
+@@ -52,6 +53,29 @@ struct port_class *diskfs_shutdown_notification_class;
+
+ struct port_bucket *diskfs_port_bucket;
+
++/* Provide a human-readable description of the given protid object. */
++error_t
++diskfs_format_debug_info (const void *port, char *buffer, size_t size)
++{
++ const struct protid *protid = port;
++ const struct port_info *pi = port;
++ struct references references;
++
++ refcounts_references (&protid->po->np->refcounts, &references);
++
++ snprintf (buffer, size,
++ "bucket: %s, class: %s"
++ ", node{inode: %"PRIu64", hard: %u, weak: %u}, path: %s",
++ pi->bucket->label,
++ pi->class->label,
++ protid->po->np->cache_id,
++ references.hard,
++ references.weak,
++ protid->po->path);
++
++ return 0;
++}
++
+ /* Call this after arguments have been parsed to initialize the
+ library. */
+ error_t
+@@ -87,13 +111,20 @@ diskfs_init_diskfs (void)
+
+ diskfs_auth_server_port = getauth ();
+
+- diskfs_protid_class = ports_create_class (diskfs_protid_rele, 0);
+- diskfs_control_class = ports_create_class (_diskfs_control_clean, 0);
+- diskfs_initboot_class = ports_create_class (0, 0);
+- diskfs_execboot_class = ports_create_class (0, 0);
+- diskfs_shutdown_notification_class = ports_create_class (0, 0);
++#define MAKE_CLASS(NAME, FN, ARG, DBG) \
++ NAME = ports_create_class ((FN), (ARG)); \
++ ports_label_class (NAME, #NAME, (DBG))
++
++ MAKE_CLASS (diskfs_protid_class, diskfs_protid_rele, NULL,
++ diskfs_format_debug_info);
++ MAKE_CLASS (diskfs_control_class, _diskfs_control_clean, NULL, NULL);
++ MAKE_CLASS (diskfs_initboot_class, NULL, NULL, NULL);
++ MAKE_CLASS (diskfs_execboot_class, NULL, NULL, NULL);
++ MAKE_CLASS (diskfs_shutdown_notification_class, NULL, NULL, NULL);
++#undef MAKE_CLASS
+
+ diskfs_port_bucket = ports_create_bucket ();
++ ports_label_bucket (diskfs_port_bucket, "diskfs_port_bucket");
+
+ _hurd_port_init (&_diskfs_exec_portcell, MACH_PORT_NULL);
+
+--
+2.1.4
+
diff --git a/debian/patches/introspection0006-libpager-annotate-objects-managed-by-libports.patch b/debian/patches/introspection0006-libpager-annotate-objects-managed-by-libports.patch
new file mode 100644
index 00000000..844bba57
--- /dev/null
+++ b/debian/patches/introspection0006-libpager-annotate-objects-managed-by-libports.patch
@@ -0,0 +1,61 @@
+From 2423b4906a7bcee05ce776364979d5ca9090fd99 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 18:33:14 +0200
+Subject: [PATCH hurd 6/9] libpager: annotate objects managed by libports
+
+Label _pager_class and provide a function which prints a
+human-readable description of a pager object.
+
+* libpager/pager-create.c (format_debug_info): New function.
+(create_class): Label _pager_class.
+---
+ libpager/pager-create.c | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/libpager/pager-create.c b/libpager/pager-create.c
+index b583f02..422e8f4 100644
+--- a/libpager/pager-create.c
++++ b/libpager/pager-create.c
+@@ -15,6 +15,8 @@
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
++#include <stdio.h>
++
+ #include "priv.h"
+
+ /* Create and return a new pager with user info UPI. */
+@@ -50,6 +52,23 @@ pager_create (struct user_pager_info *upi,
+ return p;
+ }
+
++/* Provide a human-readable description of the given pager object. */
++static error_t
++format_debug_info (const void *port, char *buffer, size_t size)
++{
++ const struct pager *pager = port;
++ const struct port_info *pi = port;
++
++ snprintf (buffer, size,
++ "bucket: %s, class: %s, may_cache: %d",
++ pi->bucket->label,
++ pi->class->label,
++ /* XXX I have no idea what might be interesting to print
++ here, but it is straight forward to add stuff. */
++ pager->may_cache);
++
++ return 0;
++}
+
+ /* This causes the function to be run at startup by compiler magic. */
+ static void create_class (void) __attribute__ ((constructor));
+@@ -58,5 +77,6 @@ static void
+ create_class ()
+ {
+ _pager_class = ports_create_class (_pager_clean, _pager_real_dropweak);
++ ports_label_class (_pager_class, "_pager_class", format_debug_info);
+ (void) &create_class; /* Avoid warning */
+ }
+--
+2.1.4
+
diff --git a/debian/patches/introspection0007-ext2fs-annotate-objects-managed-by-libports.patch b/debian/patches/introspection0007-ext2fs-annotate-objects-managed-by-libports.patch
new file mode 100644
index 00000000..09117381
--- /dev/null
+++ b/debian/patches/introspection0007-ext2fs-annotate-objects-managed-by-libports.patch
@@ -0,0 +1,99 @@
+From 9c8ddc2ff667a9d7482676eadfa321d4efb97297 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 21 May 2014 18:39:38 +0200
+Subject: [PATCH hurd 7/9] ext2fs: annotate objects managed by libports
+
+Install a specialized version of libpagers format_debug_info which
+prints more detailed information, like the nodes inode number for file
+pager objects. Also label both pager buckets.
+
+* ext2fs/pager-create.c (format_debug_info): New function.
+(create_disk_pager): Install our own format_debug_info function.
+Label both pager buckets.
+---
+ ext2fs/pager.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/ext2fs/pager.c b/ext2fs/pager.c
+index 3e080f8..b737ba7 100644
+--- a/ext2fs/pager.c
++++ b/ext2fs/pager.c
+@@ -19,10 +19,12 @@
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+ #include <unistd.h>
++#include <stdio.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <error.h>
+ #include <hurd/store.h>
++#include <inttypes.h>
+ #include "ext2fs.h"
+
+ /* XXX */
+@@ -1196,6 +1198,38 @@ disk_cache_block_is_ref (block_t block)
+ return ref;
+ }
+
++/* Provide a human-readable description of the given pager object. */
++static error_t
++format_debug_info (const void *port, char *buffer, size_t size)
++{
++ const struct pager *pager = port;
++ const struct port_info *pi = port;
++
++ if (pager->upi->type == FILE_DATA)
++ {
++ struct references references;
++ refcounts_references (&pager->upi->node->refcounts, &references);
++ snprintf (buffer, size,
++ "bucket: %s, class: %s, "
++ "node{inode: %"PRIu64", hard: %u, weak: %u}",
++ pi->bucket->label,
++ pi->class->label,
++ pager->upi->node->cache_id,
++ references.hard,
++ references.weak);
++ }
++ else
++ snprintf (buffer, size,
++ "bucket: %s, class: %s, may_cache: %d",
++ pi->bucket->label,
++ pi->class->label,
++ /* XXX I have no idea what might be interesting to print
++ here, but it is straight forward to add stuff. */
++ pager->may_cache);
++
++ return 0;
++}
++
+ /* Create the disk pager, and the file pager. */
+ void
+ create_disk_pager (void)
+@@ -1204,12 +1238,15 @@ create_disk_pager (void)
+ pthread_attr_t attr;
+ error_t err;
+
++ ports_label_class (_pager_class, "_pager_class", format_debug_info);
++
+ /* The disk pager. */
+ struct user_pager_info *upi = malloc (sizeof (struct user_pager_info));
+ if (!upi)
+ ext2_panic ("can't create disk pager: %s", strerror (errno));
+ upi->type = DISK;
+ disk_pager_bucket = ports_create_bucket ();
++ ports_label_bucket (disk_pager_bucket, "disk_pager_bucket");
+ get_hypermetadata ();
+ disk_cache_blocks = DISK_CACHE_BLOCKS;
+ disk_cache_size = disk_cache_blocks << log2_block_size;
+@@ -1219,6 +1256,7 @@ create_disk_pager (void)
+
+ /* The file pager. */
+ file_pager_bucket = ports_create_bucket ();
++ ports_label_bucket (file_pager_bucket, "file_pager_bucket");
+
+ /* Start libpagers worker threads. */
+ err = pager_start_workers (file_pager_bucket, &file_pager_requests);
+--
+2.1.4
+
diff --git a/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch b/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch
new file mode 100644
index 00000000..0a8b0260
--- /dev/null
+++ b/debian/patches/introspection0008-utils-rpctrace-support-attaching-to-servers.patch
@@ -0,0 +1,373 @@
+From 5a4a5c0807ce9b90b36e21032d5ff268b4a71f6f Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Fri, 23 May 2014 08:42:45 +0200
+Subject: [PATCH hurd 8/9] utils/rpctrace: support attaching to servers
+
+* utils/rpctrace.c (options): Add `--pid' and `--reference-port'.
+(print_contents): Prevent the translation of rights if `req' is NULL.
+We will use this to print messages in `trace_server'.
+(parse_task): New function.
+(trace_server): Mach server function that displays relayed messages.
+(trace_class_rpcs): New function that attaches to a server and starts
+tracing.
+(parse_opt): Handle `--pid' and `--reference-port'.
+(main): Handle new arguments, call trace_class_rpcs if desired.
+---
+ utils/Makefile | 5 +-
+ utils/rpctrace.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 248 insertions(+), 3 deletions(-)
+
+diff --git a/utils/Makefile b/utils/Makefile
+index 955789b..352494a 100644
+--- a/utils/Makefile
++++ b/utils/Makefile
+@@ -34,7 +34,7 @@ SRCS = shd.c ps.c settrans.c syncfs.c showtrans.c addauth.c rmauth.c \
+ nullauth.c match-options.c msgids.c rpcscan.c
+
+ OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
+-HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc
++HURDLIBS = ps ihash store fshelp ports ftpconn shouldbeinlibc introspection
+ LDLIBS += -lpthread
+ login-LDLIBS = -lutil -lcrypt
+ addauth-LDLIBS = -lcrypt
+@@ -67,7 +67,8 @@ ps w ids settrans syncfs showtrans fsysopts storeinfo login vmstat portinfo \
+
+ $(filter-out $(special-targets), $(targets)): %: %.o
+
+-rpctrace: ../libports/libports.a
++rpctrace: ../libports/libports.a \
++ ../libintrospection/libintrospection.a hurd_portUser.o
+ rpctrace rpcscan: msgids.o \
+ ../libihash/libihash.a
+ msgids-CPPFLAGS = -DDATADIR=\"${datadir}\"
+diff --git a/utils/rpctrace.c b/utils/rpctrace.c
+index d53b510..64c171a 100644
+--- a/utils/rpctrace.c
++++ b/utils/rpctrace.c
+@@ -23,6 +23,7 @@
+ #include <hurd.h>
+ #include <hurd/ports.h>
+ #include <hurd/ihash.h>
++#include <hurd/introspection.h>
+ #include <mach/message.h>
+ #include <assert.h>
+ #include <fcntl.h>
+@@ -40,14 +41,22 @@
+ #include <envz.h>
+
+ #include "msgids.h"
++#include "hurd_port_U.h"
+
+ const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace);
+
+ static unsigned strsize = 80;
++static int trace_class;
+
+ static const struct argp_option options[] =
+ {
+ {"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."},
++ {"pid", 'p', "PID", 0, "Attach to PID and trace all requests to objects "
++ "of the same class as the given reference port. This will only work "
++ "for Hurd servers implementing the introspection protocol."},
++ {"port", 'P', "PORT", 0, "Trace all requests PORT. "
++ "PORT must denote a receive right in PID."},
++ {"class", 'c', NULL, 0, "Trace all requests to the same class as PORT."},
+ {0, 's', "SIZE", 0, "Specify the maximum string size to print (the default is 80)."},
+ {0, 'E', "var[=value]", 0,
+ "Set/change (var=value) or remove (var) an environment variable among the "
+@@ -852,7 +861,7 @@ print_contents (mach_msg_header_t *inp,
+ what task that port name is meaningful in. If it's meaningful in
+ a traced task, then it refers to our intercepting port rather than
+ the original port anyway. */
+- if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name))
++ if (MACH_MSG_TYPE_PORT_ANY_RIGHT (name) && req != NULL)
+ {
+ /* These are port rights. Translate them into wrappers. */
+ mach_port_t *const portnames = data;
+@@ -1669,10 +1678,218 @@ traced_spawn (char **argv, char **envp)
+
+ return pid;
+ }
++
++/* Return the task corresponding to the user argument ARG, exiting with an
++ appriate error message if we can't. */
++static task_t
++parse_task (char *arg)
++{
++ error_t err;
++ task_t task;
++ char *arg_end;
++ pid_t pid = strtoul (arg, &arg_end, 10);
++ static process_t proc = MACH_PORT_NULL;
++
++ if (*arg == '\0' || *arg_end != '\0')
++ error (10, 0, "%s: Invalid process id", arg);
++
++ if (proc == MACH_PORT_NULL)
++ proc = getproc ();
++
++ err = proc_pid2task (proc, pid, &task);
++ if (err)
++ error (11, err, "%s", arg);
++ else if (task == MACH_PORT_NULL)
++ error (11, 0, "%s: Process %d is dead and has no task", arg, (int) pid);
++
++ return task;
++}
++
++static mach_port_t trace_notification_port;
++static mach_port_t reference_port;
++
++boolean_t
++trace_server (mach_msg_header_t *inp,
++ mach_msg_header_t *outp)
++{
++ error_t err;
++ static struct hurd_ihash ongoing_requests =
++ HURD_IHASH_INITIALIZER (HURD_IHASH_NO_LOCP);
++ struct msgid_info *info;
++ mach_port_t trace_id;
++ int is_reply;
++
++ if (inp->msgh_local_port == trace_notification_port
++ && inp->msgh_id == MACH_NOTIFY_NO_SENDERS)
++ {
++ error (0, 0, "The tracee vanished.");
++ exit (EXIT_SUCCESS);
++ }
++
++ err = introspection_extract_message (inp, &trace_id);
++ if (err)
++ {
++ error (0, err, "introspection_extract_message");
++ goto out;
++ }
++ info = msgid_info (inp->msgh_id);
++
++ /* XXX This hardcodes an assumption about reply message ids. */
++ is_reply = (inp->msgh_id / 100) % 2 == 1;
++ if (is_reply)
++ {
++ /* This looks like a traced reply or a pseudo-reply. A
++ pseudo-reply is a message containing the result of a simple
++ procedure that is only sent to us. */
++ mig_reply_header_t *reply = (mig_reply_header_t *) inp;
++
++ mach_port_t request_port;
++ request_port = hurd_ihash_find (&ongoing_requests, trace_id);
++ if (! MACH_PORT_VALID (request_port))
++ {
++ fprintf (stderr, "unsolicited reply packet with id: %d\n",
++ trace_id);
++ goto out;
++ }
++ hurd_ihash_remove (&ongoing_requests, trace_id);
++
++ if (! (trace_class || request_port == reference_port))
++ goto out;
++
++ if (last_reply_port != trace_id)
++ {
++ print_ellipsis ();
++ fprintf (ostream, "%u...", (unsigned int) trace_id);
++ }
++ last_reply_port = MACH_PORT_NULL;
++
++ fprintf (ostream, " = ");
++
++ if (reply->RetCode == 0)
++ fprintf (ostream, "0");
++ else
++ {
++ const char *str = strerror (reply->RetCode);
++ if (str == 0)
++ fprintf (ostream, "%#x", reply->RetCode);
++ else
++ fprintf (ostream, "%#x (%s)", reply->RetCode, str);
++ }
++
++ if (inp->msgh_size > sizeof *reply)
++ {
++ fprintf (ostream, " ");
++ print_contents (inp, (void *) inp + sizeof *reply, NULL);
++ }
++ fprintf (ostream, "\n");
++ }
++ else
++ {
++ /* Remember the request port. */
++ hurd_ihash_add (&ongoing_requests, trace_id, inp->msgh_local_port);
++
++ if (! (trace_class || inp->msgh_local_port == reference_port))
++ goto out;
++
++ /* This looks like a traced request. */
++ print_ellipsis ();
++ last_reply_port = trace_id;
++
++ if (info)
++ fprintf (ostream, "% 4d->%s (", inp->msgh_local_port, info->name);
++ else
++ fprintf (ostream, "% 4d->%d (", inp->msgh_local_port, inp->msgh_id);
++
++ print_contents (inp, (void *) inp + sizeof *inp, NULL);
++ fprintf (ostream, ")");
++ }
++
++ out:
++ /* vm_deallocate any out-of-band memory. */
++ mach_msg_destroy (inp);
++
++ /* Prevent mach_msg_server from sending messages. */
++ ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
++ return TRUE;
++}
++
++int
++trace_class_rpcs (mach_port_t task,
++ mach_port_t name)
++{
++ error_t err;
++ mach_port_t trace_port;
++ mach_port_t introspection_port;
++ mach_port_t previous;
++ mach_port_t port_set;
++
++ err = introspection_get_port (task, &introspection_port);
++ if (err)
++ error (13, err, "Failed to get introspection port");
++
++ if (! MACH_PORT_VALID (introspection_port))
++ error (13, 0, "The server does not implement the introspection protocol");
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
++ &trace_port);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = hurd_port_trace_class_rpcs (introspection_port, name,
++ trace_port, MACH_MSG_TYPE_MAKE_SEND);
++ if (err)
++ {
++ if (err == EINVAL)
++ error (13, 0,
++ "%d does not denote a receive right managed by libports", name);
++ else
++ error (13, err, "hurd_port_trace_class_rpcs");
++ }
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
++ &trace_notification_port);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = mach_port_request_notification (mach_task_self (),
++ trace_port,
++ MACH_NOTIFY_NO_SENDERS,
++ 0,
++ trace_notification_port,
++ MACH_MSG_TYPE_MAKE_SEND_ONCE,
++ &previous);
++ if (err)
++ error (13, err, "mach_port_request_notification");
++ assert (! MACH_PORT_VALID (previous));
++
++
++ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_PORT_SET,
++ &port_set);
++ if (err)
++ error (13, err, "mach_port_allocate");
++
++ err = mach_port_move_member (mach_task_self (), trace_port, port_set);
++ if (err)
++ error (13, err, "mach_port_move_member");
+
++ err = mach_port_move_member (mach_task_self (), trace_notification_port,
++ port_set);
++ if (err)
++ error (13, err, "mach_port_move_member");
++
++ error (0, 0, "entering service loop");
++ while (1)
++ mach_msg_server (trace_server, 0, port_set);
++
++ /* Not reached. */
++ return 0;
++}
++
+ int
+ main (int argc, char **argv, char **envp)
+ {
++ mach_port_t target_task = MACH_PORT_NULL;
++ bool nostdinc = FALSE;
+ const char *outfile = 0;
+ char **cmd_argv = 0;
+ pthread_t thread;
+@@ -1684,12 +1901,27 @@ main (int argc, char **argv, char **envp)
+ /* Parse our options... */
+ error_t parse_opt (int key, char *arg, struct argp_state *state)
+ {
++ char *arg_end;
+ switch (key)
+ {
+ case 'o':
+ outfile = arg;
+ break;
+
++ case 'p':
++ target_task = parse_task (arg);
++ break;
++
++ case 'P':
++ reference_port = strtoul (arg, &arg_end, 10);
++ if (*arg == '\0' || *arg_end != '\0')
++ argp_error (state, "Invalid port name: %s", arg);
++ break;
++
++ case 'c':
++ trace_class = 1;
++ break;
++
+ case 's':
+ strsize = atoi (arg);
+ break;
+@@ -1723,10 +1955,16 @@ main (int argc, char **argv, char **envp)
+ break;
+
+ case ARGP_KEY_NO_ARGS:
++ if (MACH_PORT_VALID (target_task))
++ break;
++
+ argp_usage (state);
+ return EINVAL;
+
+ case ARGP_KEY_ARG:
++ if (MACH_PORT_VALID (target_task))
++ argp_error (state, "Superfluous argument: %s", arg);
++
+ cmd_argv = &state->argv[state->next - 1];
+ state->next = state->argc;
+ break;
+@@ -1746,6 +1984,9 @@ main (int argc, char **argv, char **envp)
+ /* Parse our arguments. */
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0);
+
++ if (MACH_PORT_VALID (target_task) != MACH_PORT_VALID (reference_port))
++ error (10, 0, "Please specify either both -p and -P, or neither.");
++
+ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_DEAD_NAME,
+ &unknown_task);
+ assert_perror (err);
+@@ -1760,6 +2001,9 @@ main (int argc, char **argv, char **envp)
+ ostream = stderr;
+ setlinebuf (ostream);
+
++ if (MACH_PORT_VALID (target_task))
++ return trace_class_rpcs (target_task, reference_port);
++
+ traced_bucket = ports_create_bucket ();
+ traced_class = ports_create_class (&traced_clean, NULL);
+ other_class = ports_create_class (0, 0);
+--
+2.1.4
+
diff --git a/debian/patches/introspection0009-fixup_libports.patch b/debian/patches/introspection0009-fixup_libports.patch
new file mode 100644
index 00000000..afdd0456
--- /dev/null
+++ b/debian/patches/introspection0009-fixup_libports.patch
@@ -0,0 +1,122 @@
+From c899d36cf0358036428e0f545da0ea1bff812022 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Thu, 24 Sep 2015 18:23:28 +0200
+Subject: [PATCH hurd 9/9] fixup_libports
+
+---
+ libports/introspection.c | 35 ++++++++++++++++++++---------------
+ libports/manage-multithread.c | 6 ++++--
+ libports/manage-one-thread.c | 6 ++++--
+ libports/ports.h | 1 +
+ 4 files changed, 29 insertions(+), 19 deletions(-)
+
+diff --git a/libports/introspection.c b/libports/introspection.c
+index 912c768..07f8624 100644
+--- a/libports/introspection.c
++++ b/libports/introspection.c
+@@ -71,24 +71,29 @@ service_introspection_requests (void *arg)
+ return NULL;
+ }
+
+-/* Start the introspection server before main is called. */
+-static void __attribute__ ((constructor))
+-init (void)
++/* Start the introspection server if it is not already running. */
++void
++_ports_start_introspection_server (void)
+ {
++ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
++ static int initialized = 0;
+ error_t err;
+-
+ pthread_t thread;
+- pthread_attr_t attr;
+-#define STACK_SIZE (64 * 1024)
+- pthread_attr_init (&attr);
+- pthread_attr_setstacksize (&attr, STACK_SIZE);
+-#undef STACK_SIZE
+-
+- err = pthread_create (&thread, &attr,
+- service_introspection_requests, NULL);
+- if (err)
+- error (1, err, "pthread_create");
+- pthread_detach (thread);
++
++ pthread_mutex_lock (&lock);
++ if (! initialized)
++ {
++ err = pthread_create (&thread, NULL,
++ service_introspection_requests, NULL);
++ if (err)
++ error (0, err, "Error starting introspection server");
++ else
++ {
++ pthread_detach (thread);
++ initialized = 1;
++ }
++ }
++ pthread_mutex_unlock (&lock);
+ }
+
+ /* Return the number of hard and weak references of the object
+diff --git a/libports/manage-multithread.c b/libports/manage-multithread.c
+index 8707d98..d2e7dbe 100644
+--- a/libports/manage-multithread.c
++++ b/libports/manage-multithread.c
+@@ -214,8 +214,7 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
+ }
+ ports_port_deref (pi);
+
+- if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
+- && outp->RetCode != MIG_NO_REPLY)
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+ introspection_trace_message (trace_port, outp, trace_id);
+ }
+ else
+@@ -291,5 +290,8 @@ ports_manage_port_operations_multithread (struct port_bucket *bucket,
+ master thread from going away. */
+ global_timeout = 0;
+
++ /* Make sure the introspection server is running. */
++ _ports_start_introspection_server ();
++
+ thread_function ((void *) 1);
+ }
+diff --git a/libports/manage-one-thread.c b/libports/manage-one-thread.c
+index 55aa378..86d575e 100644
+--- a/libports/manage-one-thread.c
++++ b/libports/manage-one-thread.c
+@@ -104,8 +104,7 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
+ }
+ ports_port_deref (pi);
+
+- if (__builtin_expect (MACH_PORT_VALID (trace_port), 0)
+- && outp->RetCode != MIG_NO_REPLY)
++ if (__builtin_expect (MACH_PORT_VALID (trace_port), 0))
+ introspection_trace_message (trace_port, outp, trace_id);
+ }
+ else
+@@ -125,6 +124,9 @@ ports_manage_port_operations_one_thread (struct port_bucket *bucket,
+ zero. */
+ timeout = 0;
+
++ /* Make sure the introspection server is running. */
++ _ports_start_introspection_server ();
++
+ _ports_thread_online (&bucket->threadpool, &thread);
+ do
+ err = mach_msg_server_timeout (internal_demuxer, 0, bucket->portset,
+diff --git a/libports/ports.h b/libports/ports.h
+index a31b894..e61b38c 100644
+--- a/libports/ports.h
++++ b/libports/ports.h
+@@ -496,5 +496,6 @@ void _ports_complete_deallocate (struct port_info *);
+ error_t _ports_create_port_internal (struct port_class *, struct port_bucket *,
+ size_t, void *, int);
+ error_t _ports_trace_message (mach_port_t, const mach_msg_header_t *);
++void _ports_start_introspection_server (void);
+
+ #endif
+--
+2.1.4
+
diff --git a/debian/patches/series b/debian/patches/series
index 08c3dc14..9150b813 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -63,3 +63,12 @@ exec_filename0001-Add-a-new-exec_exec_file_name-RPC.patch
exec_filename0002-Add-a-file_exec_file_name-RPC.patch
exec_filename0003-Use-the-new-_hurd_exec_file_name-function.patch
exec_filename0004-This-patch-is-an-amendment-of-exec_filename_exec.pat.patch
+introspection0001-hurd-add-an-Hurd-server-introspection-protocol.patch
+introspection0002-libintrospection-a-library-for-Hurd-server-introspec.patch
+introspection0003-libports-implement-the-Hurd-server-introspection-pro.patch
+introspection0004-utils-implement-portinfo-query-process.patch
+introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch
+introspection0006-libpager-annotate-objects-managed-by-libports.patch
+introspection0007-ext2fs-annotate-objects-managed-by-libports.patch
+introspection0008-utils-rpctrace-support-attaching-to-servers.patch
+introspection0009-fixup_libports.patch