diff --git a/lib/modules/Debug.pmod/module.pmod b/lib/modules/Debug.pmod/module.pmod
index d986e994976d324c5808a4b5a1daedb2b981862f..81528332b921c85acc378b563acb6d415dfd82a5 100644
--- a/lib/modules/Debug.pmod/module.pmod
+++ b/lib/modules/Debug.pmod/module.pmod
@@ -11,6 +11,7 @@ constant describe_program = _describe_program;
 constant debug = _debug;
 constant optimizer_debug = _optimizer_debug;
 constant assembler_debug = _assembler_debug;
+constant disassemble = Builtin._disassemble;
 constant dump_program_tables = _dump_program_tables;
 constant locate_references = _locate_references;
 constant describe = _describe;
diff --git a/src/builtin.cmod b/src/builtin.cmod
index ee5d1e7571544fae158e3a194941d6dc064a3e00..a833c767969944490c045c1ae09ec7c63f714ffe 100644
--- a/src/builtin.cmod
+++ b/src/builtin.cmod
@@ -30,6 +30,7 @@
 #include "gc.h"
 #include "block_alloc.h"
 #include "pikecode.h"
+#include "opcodes.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -1687,6 +1688,66 @@ PIKEFUN void _putenv (string var, void|string val)
 #endif /* !USE_SETENV */
 }
 
+#if defined(PIKE_DEBUG) && defined(PIKE_PORTABLE_BYTECODE)
+
+/*! @decl void disassemble(function fun)
+ *! @belongs Debug
+ *!
+ *!   Disassemble a Pike function to @[Stdio.stderr].
+ *!
+ *! @note
+ *!   This function is only available if the Pike runtime
+ *!   has been compiled with debug enabled.
+ */
+PIKEFUN void _disassemble(function fun)
+{
+  if ((TYPEOF(*fun) != T_FUNCTION) ||
+      (SUBTYPEOF(*fun) == FUNCTION_BUILTIN)) {
+    fprintf(stderr,
+	    "Disassembly only supported for functions implemented in Pike.\n");
+  } else if (!fun->u.object->prog) {
+    fprintf(stderr, "Function in destructed object.\n");
+  } else {
+    int f = SUBTYPEOF(*fun);
+    struct reference *ptr = PTR_FROM_INT(fun->u.object->prog, f);
+    struct program *p = PROG_FROM_PTR(fun->u.object->prog, ptr);
+    struct identifier *id = p->identifiers + ptr->identifier_offset;
+    if (id->func.offset >= 0) {
+      struct pike_string *tripples =
+	p->strings[read_program_data(p->program + id->func.offset, -1)];
+      switch(tripples->size_shift) {
+#define CASE(SHIFT)					\
+	case SHIFT:					\
+	  {						\
+	    PIKE_CONCAT(p_wchar, SHIFT) *str =		\
+	      PIKE_CONCAT(STR, SHIFT)(tripples);	\
+	    int i=0;					\
+	    while(i < tripples->len) {			\
+	      fprintf(stderr, "@@@ %d: %s, %d, %d\n",	\
+		      i/3,				\
+		      instrs[*str - F_OFFSET].		\
+		      name,				\
+		      str[1], str[2]);			\
+	      str += 3;					\
+	      i += 3;					\
+	    }						\
+	  }						\
+	  break
+	CASE(0);
+	CASE(1);
+	CASE(2);
+#undef CASE
+      }
+    } else {
+      fprintf(stderr, "Prototype.\n");
+    }
+  }
+  pop_n_elems(args);
+  push_int(0);
+}
+
+#endif /* PIKE_DEBUG && PIKE_PORTABLE_BYTECODE */
+
 /*
  * Backtrace handling.
  */