public inbox for frysk-cvs@sourceware.org
help / color / mirror / Atom feed
From: cagney@sourceware.org
To: frysk-cvs@sourceware.org
Subject: [SCM]  master: Implement frysk.sys.ptrace in jni.
Date: Wed, 14 May 2008 17:10:00 -0000	[thread overview]
Message-ID: <20080514171053.26157.qmail@sourceware.org> (raw)

The branch, master has been updated
       via  9e07b5e5c951f582ed2e466295376bafc6c46df3 (commit)
      from  9da8189a51b382e4d3e46fbf770808d8592e357e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email.

- Log -----------------------------------------------------------------
commit 9e07b5e5c951f582ed2e466295376bafc6c46df3
Author: Andrew Cagney <cagney@redhat.com>
Date:   Wed May 14 13:09:40 2008 -0400

    Implement frysk.sys.ptrace in jni.
    
    frysk-sys/ChangeLog
    2008-05-14  Andrew Cagney  <cagney@redhat.com>
    
    	* Makefile.am (JNIXX_CLASSES): Add
    	java.lang.ArrayIndexOutOfBoundsException.
    
    frysk-sys/frysk/jnixx/ChangeLog
    2008-05-14  Andrew Cagney  <cagney@redhat.com>
    
    	* chars.hxx (class ByteArrayElements): New.
    	* bounds.hxx: New.
    	* JniBindings.java: Generate GetArrayLength, and Throw.
    
    frysk-sys/frysk/sys/ptrace/ChangeLog
    2008-05-14  Andrew Cagney  <cagney@redhat.com>
    
    	* jni/Ptrace.cxx: Convert to JNI.
    	* jni/AddressSpace.cxx: Convert to JNI.
    	* jni/RegisterSet.cxx: Covert to JNI.
    	* jni/Utrace.cxx: Delete.

-----------------------------------------------------------------------

Summary of changes:
 frysk-sys/ChangeLog                                |    5 +
 frysk-sys/Makefile.am                              |    1 +
 frysk-sys/frysk/jnixx/ChangeLog                    |    6 +
 frysk-sys/frysk/jnixx/JniBindings.java             |   22 +++-
 .../jni/AddressSpace.cxx => jnixx/bounds.hxx}      |   29 ++++-
 frysk-sys/frysk/jnixx/chars.hxx                    |   26 ++++
 frysk-sys/frysk/sys/ptrace/ChangeLog               |    7 +
 frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx    |  155 +++++++++++++++++++-
 frysk-sys/frysk/sys/ptrace/jni/Ptrace.cxx          |  117 +++++++++++++++-
 .../ptrace/jni/{AddressSpace.cxx => Ptrace.hxx}    |    2 +-
 frysk-sys/frysk/sys/ptrace/jni/RegisterSet.cxx     |   55 +++++++-
 11 files changed, 419 insertions(+), 6 deletions(-)
 copy frysk-sys/frysk/{sys/ptrace/jni/AddressSpace.cxx => jnixx/bounds.hxx} (69%)
 copy frysk-sys/frysk/sys/ptrace/jni/{AddressSpace.cxx => Ptrace.hxx} (97%)

First 500 lines of diff:
diff --git a/frysk-sys/ChangeLog b/frysk-sys/ChangeLog
index 22e6cec..7fdfce7 100644
--- a/frysk-sys/ChangeLog
+++ b/frysk-sys/ChangeLog
@@ -1,3 +1,8 @@
+2008-05-14  Andrew Cagney  <cagney@redhat.com>
+
+	* Makefile.am (JNIXX_CLASSES): Add
+	java.lang.ArrayIndexOutOfBoundsException.
+
 2008-05-13  Andrew Cagney  <cagney@redhat.com>
 
 	* Makefile.am (JNIXX_CLASSES): Add
diff --git a/frysk-sys/Makefile.am b/frysk-sys/Makefile.am
index bb39422..cd10704 100644
--- a/frysk-sys/Makefile.am
+++ b/frysk-sys/Makefile.am
@@ -73,6 +73,7 @@ lib/unwind/Unwind%.java: lib/unwind/Unwind.java
 # jnixx's auto-detect algorithm misses hidden class references,
 # explicitly add them here.
 JNIXX_CLASSES += frysk.sys.ProcessIdentifierFactory
+JNIXX_CLASSES += java.lang.ArrayIndexOutOfBoundsException
 \f
 
 # Quick hack to get a test JNI program up-and-running; as a package is
diff --git a/frysk-sys/frysk/jnixx/ChangeLog b/frysk-sys/frysk/jnixx/ChangeLog
index 61f470a..84ffdc5 100644
--- a/frysk-sys/frysk/jnixx/ChangeLog
+++ b/frysk-sys/frysk/jnixx/ChangeLog
@@ -1,3 +1,9 @@
+2008-05-14  Andrew Cagney  <cagney@redhat.com>
+
+	* chars.hxx (class ByteArrayElements): New.
+	* bounds.hxx: New.
+	* JniBindings.java: Generate GetArrayLength, and Throw.
+
 2008-05-13  Andrew Cagney  <cagney@redhat.com>
 
 	* PrintDeclarations.java: Do not generate non-ENV wrappers.
diff --git a/frysk-sys/frysk/jnixx/JniBindings.java b/frysk-sys/frysk/jnixx/JniBindings.java
index 7464cb7..40026dc 100644
--- a/frysk-sys/frysk/jnixx/JniBindings.java
+++ b/frysk-sys/frysk/jnixx/JniBindings.java
@@ -207,6 +207,18 @@ class JniBindings {
 	     })
 
 	/**
+	 * java.lang.Throwable
+	 */
+	.put(Throwable.class, false,
+	     null, "Throw",
+	     new String[] {
+		 "::jnixx::env", "env",
+	     },
+	     new Object[] {
+		 "env.Throw((jthrowable) _object);"
+	     })
+
+	/**
 	 * java.lang.String
 	 */
 	// NewString
@@ -302,7 +314,7 @@ class JniBindings {
 			 "return " + type + "Array(env, env.New" + Type + "Array(length));",
 		     })
 		.put(types[i], false,
-		     "const j" + type + "*", "GetElements",
+		     "j" + type + "*", "GetElements",
 		     new String[] {
 			 "::jnixx::env", "env",
 			 "jboolean*", "isCopy",
@@ -311,6 +323,14 @@ class JniBindings {
 			 "return env.Get" + Type + "ArrayElements((j" + type + "Array) _object, isCopy);"
 		     })
 		.put(types[i], false,
+		     "jsize", "GetArrayLength",
+		     new String[] {
+			 "::jnixx::env", "env",
+		     },
+		     new Object[] {
+			 "return env.GetArrayLength((j" + type + "Array) _object);"
+		     })
+		.put(types[i], false,
 		     null, "ReleaseElements",
 		     new String[] {
 			 "::jnixx::env", "env",
diff --git a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx b/frysk-sys/frysk/jnixx/bounds.hxx
similarity index 69%
copy from frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
copy to frysk-sys/frysk/jnixx/bounds.hxx
index b358932..9f84d5e 100644
--- a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
+++ b/frysk-sys/frysk/jnixx/bounds.hxx
@@ -37,4 +37,31 @@
 // version and license this file solely under the GPL without
 // exception.
 
-#include "jni.hxx"
+/**
+ * Given an array, verify an attempt to access elements.  If the
+ * access is out-of-bounds throw an exception.
+ */
+
+inline void verifyBounds(::jnixx::env env, ::jnixx::byteArray data,
+			 jint stop) {
+  if (stop < 0) {
+    ::java::lang::ArrayIndexOutOfBoundsException::New(env, stop).Throw(env);
+  }
+  if (stop > data.GetArrayLength(env)) {
+    ::java::lang::ArrayIndexOutOfBoundsException::New(env, stop).Throw(env);
+  }
+}
+
+inline void verifyBounds(::jnixx::env env, ::jnixx::byteArray data,
+			 jint start, jint length) {
+  if (start < 0) {
+    ::java::lang::ArrayIndexOutOfBoundsException::New(env, start).Throw(env);
+  }
+  if (start >= data.GetArrayLength(env)) {
+    ::java::lang::ArrayIndexOutOfBoundsException::New(env, start).Throw(env);
+  }
+  if (length < 0) {
+    ::java::lang::ArrayIndexOutOfBoundsException::New(env, length).Throw(env);
+  }
+  verifyBounds(env, data, start + length);
+}
diff --git a/frysk-sys/frysk/jnixx/chars.hxx b/frysk-sys/frysk/jnixx/chars.hxx
index 5c44b81..f00cf2c 100644
--- a/frysk-sys/frysk/jnixx/chars.hxx
+++ b/frysk-sys/frysk/jnixx/chars.hxx
@@ -88,3 +88,29 @@ public:
     free();
   }
 };
+
+class ByteArrayElements {
+private:
+  ::jnixx::byteArray bytes;
+  ::jnixx::env env;
+public:
+  jbyte* p;
+  ByteArrayElements(::jnixx::env env, ::jnixx::byteArray bytes) {
+    this->bytes = bytes;
+    this->env = env;
+    if (bytes != NULL) {
+      this->p = bytes.GetElements(env, NULL);
+    } else {
+      this->p = NULL;
+    }
+  }
+  void release() {
+    if (p != NULL) {
+      bytes.ReleaseElements(env, p, 0);
+      p = NULL;
+    }
+  }
+  ~ByteArrayElements() {
+    release();
+  }
+};
diff --git a/frysk-sys/frysk/sys/ptrace/ChangeLog b/frysk-sys/frysk/sys/ptrace/ChangeLog
index 4e9675f..3fa5f68 100644
--- a/frysk-sys/frysk/sys/ptrace/ChangeLog
+++ b/frysk-sys/frysk/sys/ptrace/ChangeLog
@@ -1,3 +1,10 @@
+2008-05-14  Andrew Cagney  <cagney@redhat.com>
+
+	* jni/Ptrace.cxx: Convert to JNI.
+	* jni/AddressSpace.cxx: Convert to JNI.
+	* jni/RegisterSet.cxx: Covert to JNI.
+	* jni/Utrace.cxx: Delete.
+
 2008-05-07  Andrew Cagney  <cagney@redhat.com>
 
 	* jni/AddressSpace.cxx: Include jni.hxx.
diff --git a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx b/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
index b358932..4177164 100644
--- a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
+++ b/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2008, Red Hat Inc.
+// Copyright 2005, 2006, 2007, 2008, Red Hat Inc.
 //
 // FRYSK is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by
@@ -37,4 +37,157 @@
 // version and license this file solely under the GPL without
 // exception.
 
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include "linux.ptrace.h"
+#include <string.h>
+
 #include "jni.hxx"
+#include "frysk/jnixx/bounds.hxx"
+#include "frysk/jnixx/chars.hxx"
+
+#include "frysk/sys/ptrace/jni/Ptrace.hxx"
+
+using namespace java::lang;
+
+union word {
+  long l;
+  uint8_t b[sizeof (long)];
+};
+
+jint
+frysk::sys::ptrace::AddressSpace::peek(::jnixx::env env, jint pid, jlong addr) {
+  union word w;
+  long paddr = addr & -sizeof(long);
+#if DEBUG
+  fprintf(stderr, "peek 0x%lx paddr 0x%lx", (long)addr, paddr);
+#endif
+  w.l = ptraceOp(env, GetPtPeek(env), pid, (void*)paddr, 0);
+#if DEBUG
+  fprintf(stderr, " word 0x%lx", w.l);
+#endif
+  int index = addr & (sizeof(long) - 1);
+#if DEBUG
+  fprintf(stderr, " index %d", index);
+#endif
+  uint8_t byte = w.b[index];
+#if DEBUG
+  fprintf(stderr, " byte %d/0x%x\n", byte, byte);
+#endif
+  return byte;
+}
+
+void
+frysk::sys::ptrace::AddressSpace::poke(::jnixx::env env, jint pid, jlong addr, jint data) {
+  // Implement read-modify-write
+  union word w;
+#if DEBUG
+  fprintf(stderr, "poke 0x%x", (int)(data & 0xff));
+#endif
+  long paddr = addr & -sizeof(long);
+#if DEBUG
+  fprintf(stderr, " addr 0x%lx paddr 0x%lx", (long)addr, paddr);
+#endif
+  w.l = ptraceOp(env, GetPtPeek(env), pid, (void*)paddr, 0);
+#if DEBUG
+  fprintf(stderr, " word 0x%lx", w.l);
+#endif
+  int index = addr & (sizeof(long) - 1);
+#if DEBUG
+  fprintf (stderr, " index %d", index);
+#endif
+  w.b[index] = data;
+#if DEBUG
+  fprintf(stderr, " word 0x%lx\n", w.l);
+#endif
+  ptraceOp(env, GetPtPoke(env), pid, (void*)(addr & -sizeof(long)), w.l);
+}
+
+void
+frysk::sys::ptrace::AddressSpace::transfer(::jnixx::env env,
+					   jint op, jint pid, jlong addr,
+					   ::jnixx::byteArray bytes,
+					   jint offset, jint length) {
+  const int ptPeek = GetPtPeek(env);
+  const int ptPoke = GetPtPoke(env);
+  verifyBounds(env, bytes, offset, length);
+  // Somewhat more clueful implementation
+  for (jlong i = 0; i < length;) {
+#if DEBUG
+    fprintf(stderr,
+	     "transfer pid %d addr 0x%lx length %d offset %d op %d (%s)",
+	     (int)pid, (long)addr, (int)length, (int)offset,
+	     (int)op, op_as_string(op));
+#endif
+
+    union word w;
+    unsigned long waddr = addr & -sizeof(long);
+    unsigned long woff = (addr - waddr);
+    unsigned long remaining = length - i;
+    unsigned long wend;
+    if (remaining > sizeof(long) - woff)
+      wend = sizeof(long);
+    else
+      wend = woff + remaining;
+    long wlen = wend - woff;
+
+#if DEBUG
+    fprintf(stderr,
+	     " i %ld waddr 0x%lx woff %lu wend %lu remaining %lu wlen %lu",
+	     (long)i, waddr, woff, wend, remaining, wlen);
+#endif
+
+    // Either a peek; or a partial write requiring read/modify/write.
+    if (op == ptPeek || woff != 0 || wend != sizeof(long)) {
+	w.l = ptraceOp(env, ptPeek, pid, (void*)waddr, 0);
+#if DEBUG
+	fprintf(stderr, " peek 0x%lx", w.l);
+#endif
+      }
+
+    // extract or modify
+    ByteArrayElements elements = ByteArrayElements(env, bytes);
+    if (op == ptPeek)
+      memcpy(offset + i + elements.p, &w.b[woff], wlen);
+    else {
+      memcpy(&w.b[woff], offset + i + elements.p, wlen);
+#if DEBUG
+      fprintf(stderr, " poke 0x%lx", w.l);
+#endif
+      w.l = ptraceOp(env, ptPoke, pid, (void*)waddr, w.l);
+    }
+    elements.release();
+
+    i += wlen;
+    addr += wlen;
+
+#if DEBUG
+    fprintf(stderr, "\n");
+#endif
+  }
+}
+
+frysk::sys::ptrace::AddressSpace
+frysk::sys::ptrace::AddressSpace::text(::jnixx::env env) {
+  return frysk::sys::ptrace::AddressSpace::New(env, -1UL,
+					       String::NewStringUTF(env, "TEXT"),
+					       PTRACE_PEEKTEXT,
+					       PTRACE_POKETEXT);
+}
+
+frysk::sys::ptrace::AddressSpace
+frysk::sys::ptrace::AddressSpace::data(::jnixx::env env) {
+  return frysk::sys::ptrace::AddressSpace::New(env, -1UL,
+					       String::NewStringUTF(env, "DATA"),
+					       PTRACE_PEEKDATA,
+					       PTRACE_POKEDATA);
+}
+
+frysk::sys::ptrace::AddressSpace
+frysk::sys::ptrace::AddressSpace::usr(::jnixx::env env) {
+  return frysk::sys::ptrace::AddressSpace::New(env, -1UL,
+					       String::NewStringUTF(env, "USR"),
+					       PTRACE_PEEKUSR,
+					       PTRACE_POKEUSR);
+}
diff --git a/frysk-sys/frysk/sys/ptrace/jni/Ptrace.cxx b/frysk-sys/frysk/sys/ptrace/jni/Ptrace.cxx
index b358932..d6726ed 100644
--- a/frysk-sys/frysk/sys/ptrace/jni/Ptrace.cxx
+++ b/frysk-sys/frysk/sys/ptrace/jni/Ptrace.cxx
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2008, Red Hat Inc.
+// Copyright 2005, 2006, 2007, 2008, Red Hat Inc.
 //
 // FRYSK is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License as published by
@@ -37,4 +37,119 @@
 // version and license this file solely under the GPL without
 // exception.
 
+#include <errno.h>
+#include <sys/ptrace.h>
+#include "linux.ptrace.h"
+
 #include "jni.hxx"
+
+#include "frysk/sys/ptrace/jni/Ptrace.hxx"
+
+#include "frysk/jnixx/exceptions.hxx"
+
+static const char*
+op_as_string(int op) {
+  switch(op) {
+#define OP(NAME) case NAME: return #NAME
+    OP(PTRACE_ATTACH);
+    OP(PTRACE_DETACH);
+    OP(PTRACE_SINGLESTEP);
+    OP(PTRACE_CONT);
+    OP(PTRACE_SYSCALL);
+#if defined(__i386__) || defined(__x86_64__)
+    OP(PTRACE_GETREGS);
+    OP(PTRACE_SETREGS);
+    OP(PTRACE_GETFPREGS);
+    OP(PTRACE_SETFPREGS);
+#endif
+#if defined(__i386__)
+    OP(PTRACE_GETFPXREGS);
+    OP(PTRACE_SETFPXREGS);
+#endif
+    OP(PTRACE_GETEVENTMSG);
+    OP(PTRACE_SETOPTIONS);
+    OP(PTRACE_PEEKDATA);
+    OP(PTRACE_POKEDATA);
+    OP(PTRACE_PEEKTEXT);
+    OP(PTRACE_POKETEXT);
+    OP(PTRACE_PEEKUSR);
+    OP(PTRACE_POKEUSR);
+  default: return "<unknown>";
+#undef OP
+  }
+}
+
+long
+ptraceOp(::jnixx::env env, int op, int pid, void* addr, long data) {
+  errno = 0;
+  long result = ::ptrace ((enum __ptrace_request) op, pid, addr, data);
+  if (errno != 0)
+    errnoException(env, errno, "ptrace",
+		   "op 0x%x (%s), pid %d, addr 0x%lx, data 0x%lx",
+		   op, op_as_string(op), pid, (long)addr, data);
+  return result;
+}
+
+void
+frysk::sys::ptrace::Ptrace::attach(::jnixx::env env, jint pid) {
+  ptraceOp(env, PTRACE_ATTACH, pid, NULL, 0);
+}
+
+void
+frysk::sys::ptrace::Ptrace::detach(::jnixx::env env, jint pid, jint sig) {
+  ptraceOp(env, PTRACE_DETACH, pid, NULL, sig);
+} 
+
+void
+frysk::sys::ptrace::Ptrace::singleStep(::jnixx::env env, jint pid, jint sig) {
+  ptraceOp(env, PTRACE_SINGLESTEP, pid, NULL, sig);
+} 
+
+void
+frysk::sys::ptrace::Ptrace::cont(::jnixx::env env, jint pid, jint sig) {
+  ptraceOp(env, PTRACE_CONT, pid, NULL, sig);
+}
+
+void
+frysk::sys::ptrace::Ptrace::sysCall(::jnixx::env env, jint pid, jint sig) {
+  ptraceOp(env, PTRACE_SYSCALL, pid, NULL, sig);
+}
+
+jlong
+frysk::sys::ptrace::Ptrace::getEventMsg(::jnixx::env env, jint pid) {
+  /* Note: PTRACE_GETEVENTMSG ends up calling the function
+     kernel/ptrace.c: ptrace_ptraceOp(env, ) and that uses put_user to store
+     child->ptrace_message write sizeof(ptrace_message) bytes into the
+     MESSAGE parameter.  include/linux/sched.h declares ptrace_message
+     as a long.  */
+  long msg;
+  ptraceOp(env, PTRACE_GETEVENTMSG, pid, NULL, (long) &msg);
+  return msg;
+}
+\f
+void
+frysk::sys::ptrace::Ptrace::setOptions(::jnixx::env env,
+				       jint pid, jlong options) {
+  ptraceOp(env, PTRACE_SETOPTIONS, pid, 0, options);
+}
+
+jlong
+frysk::sys::ptrace::Ptrace::optionTraceClone(::jnixx::env env) {
+  return PTRACE_O_TRACECLONE;
+}
+jlong
+frysk::sys::ptrace::Ptrace::optionTraceFork(::jnixx::env env) {
+  return PTRACE_O_TRACEFORK;
+}
+jlong
+frysk::sys::ptrace::Ptrace::optionTraceExit(::jnixx::env env) {
+  return PTRACE_O_TRACEEXIT;
+}
+jlong
+frysk::sys::ptrace::Ptrace::optionTraceSysgood(::jnixx::env env) {
+  return PTRACE_O_TRACESYSGOOD;
+}
+jlong
+frysk::sys::ptrace::Ptrace::optionTraceExec(::jnixx::env env) {
+  return PTRACE_O_TRACEEXEC;
+}
diff --git a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx b/frysk-sys/frysk/sys/ptrace/jni/Ptrace.hxx
similarity index 97%
copy from frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
copy to frysk-sys/frysk/sys/ptrace/jni/Ptrace.hxx
index b358932..be134ef 100644
--- a/frysk-sys/frysk/sys/ptrace/jni/AddressSpace.cxx
+++ b/frysk-sys/frysk/sys/ptrace/jni/Ptrace.hxx
@@ -37,4 +37,4 @@
 // version and license this file solely under the GPL without
 // exception.
 
-#include "jni.hxx"
+extern long ptraceOp(::jnixx::env, int, int, void*, long);
diff --git a/frysk-sys/frysk/sys/ptrace/jni/RegisterSet.cxx b/frysk-sys/frysk/sys/ptrace/jni/RegisterSet.cxx
index b358932..d44b1df 100644
--- a/frysk-sys/frysk/sys/ptrace/jni/RegisterSet.cxx
+++ b/frysk-sys/frysk/sys/ptrace/jni/RegisterSet.cxx
@@ -1,6 +1,6 @@
 // This file is part of the program FRYSK.
 //
-// Copyright 2008, Red Hat Inc.
+// Copyright 2005, 2006, 2007, 2008, Red Hat Inc.
 //


hooks/post-receive
--
frysk system monitor/debugger


                 reply	other threads:[~2008-05-14 17:10 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080514171053.26157.qmail@sourceware.org \
    --to=cagney@sourceware.org \
    --cc=frysk-cvs@sourceware.org \
    --cc=frysk@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).