From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tom@tromey.com>
Subject: [PATCH 5/9] Remove addrmap wrapper functions
Date: Sat, 16 Apr 2022 10:58:17 -0600 [thread overview]
Message-ID: <20220416165821.3648899-6-tom@tromey.com> (raw)
In-Reply-To: <20220416165821.3648899-1-tom@tromey.com>
This removes the various addrmap wrapper functions in favor of simple
method calls on the objects themselves.
---
gdb/addrmap.c | 60 ++++-----------------
gdb/addrmap.h | 109 +++++++++++++++++---------------------
gdb/block.c | 2 +-
gdb/buildsym.c | 4 +-
gdb/dwarf2/cooked-index.h | 4 +-
gdb/dwarf2/index-write.c | 2 +-
gdb/dwarf2/read.c | 30 +++++------
gdb/inline-frame.c | 3 +-
gdb/objfiles.c | 2 +-
gdb/psymtab.c | 3 +-
gdb/symtab.c | 2 +-
11 files changed, 82 insertions(+), 139 deletions(-)
diff --git a/gdb/addrmap.c b/gdb/addrmap.c
index e956b00ac7c..5ce7213824e 100644
--- a/gdb/addrmap.c
+++ b/gdb/addrmap.c
@@ -27,44 +27,6 @@
gdb_static_assert (sizeof (splay_tree_key) >= sizeof (CORE_ADDR *));
gdb_static_assert (sizeof (splay_tree_value) >= sizeof (void *));
-\f
-void
-addrmap_set_empty (struct addrmap *map,
- CORE_ADDR start, CORE_ADDR end_inclusive,
- void *obj)
-{
- map->set_empty (start, end_inclusive, obj);
-}
-
-
-void *
-addrmap_find (struct addrmap *map, CORE_ADDR addr)
-{
- return map->find (addr);
-}
-
-
-struct addrmap *
-addrmap_create_fixed (struct addrmap *original, struct obstack *obstack)
-{
- return original->create_fixed (obstack);
-}
-
-
-/* Relocate all the addresses in MAP by OFFSET. (This can be applied
- to either mutable or immutable maps.) */
-void
-addrmap_relocate (struct addrmap *map, CORE_ADDR offset)
-{
- map->relocate (offset);
-}
-
-
-int
-addrmap_foreach (struct addrmap *map, addrmap_foreach_fn fn)
-{
- return map->foreach (fn);
-}
\f
/* Fixed address maps. */
@@ -313,7 +275,7 @@ addrmap_fixed::addrmap_fixed (struct obstack *obstack, addrmap_mutable *mut)
size_t transition_count = 0;
/* Count the number of transitions in the tree. */
- addrmap_foreach (mut, [&] (CORE_ADDR start, void *obj)
+ mut->foreach ([&] (CORE_ADDR start, void *obj)
{
++transition_count;
return 0;
@@ -331,7 +293,7 @@ addrmap_fixed::addrmap_fixed (struct obstack *obstack, addrmap_mutable *mut)
/* Copy all entries from the splay tree to the array, in order
of increasing address. */
- addrmap_foreach (mut, [&] (CORE_ADDR start, void *obj)
+ mut->foreach ([&] (CORE_ADDR start, void *obj)
{
transitions[num_transitions].addr = start;
transitions[num_transitions].value = obj;
@@ -482,7 +444,7 @@ addrmap_dump (struct addrmap *map, struct ui_file *outfile, void *payload)
return 0;
};
- addrmap_foreach (map, callback);
+ map->foreach (callback);
}
#if GDB_SELF_TEST
@@ -502,7 +464,7 @@ core_addr (void *p)
do \
{ \
for (unsigned i = LOW; i <= HIGH; ++i) \
- SELF_CHECK (addrmap_find (MAP, core_addr (&ARRAY[i])) == VAL); \
+ SELF_CHECK (MAP->find (core_addr (&ARRAY[i])) == VAL); \
} \
while (0)
@@ -528,14 +490,13 @@ test_addrmap ()
CHECK_ADDRMAP_FIND (map, array, 0, 19, nullptr);
/* Insert address range into mutable addrmap. */
- addrmap_set_empty (map, core_addr (&array[10]), core_addr (&array[12]),
- val1);
+ map->set_empty (core_addr (&array[10]), core_addr (&array[12]), val1);
CHECK_ADDRMAP_FIND (map, array, 0, 9, nullptr);
CHECK_ADDRMAP_FIND (map, array, 10, 12, val1);
CHECK_ADDRMAP_FIND (map, array, 13, 19, nullptr);
/* Create corresponding fixed addrmap. */
- struct addrmap *map2 = addrmap_create_fixed (map, &temp_obstack);
+ struct addrmap *map2 = map->create_fixed (&temp_obstack);
SELF_CHECK (map2 != nullptr);
CHECK_ADDRMAP_FIND (map2, array, 0, 9, nullptr);
CHECK_ADDRMAP_FIND (map2, array, 10, 12, val1);
@@ -554,18 +515,17 @@ test_addrmap ()
SELF_CHECK (false);
return 0;
};
- SELF_CHECK (addrmap_foreach (map, callback) == 0);
- SELF_CHECK (addrmap_foreach (map2, callback) == 0);
+ SELF_CHECK (map->foreach (callback) == 0);
+ SELF_CHECK (map2->foreach (callback) == 0);
/* Relocate fixed addrmap. */
- addrmap_relocate (map2, 1);
+ map2->relocate (1);
CHECK_ADDRMAP_FIND (map2, array, 0, 10, nullptr);
CHECK_ADDRMAP_FIND (map2, array, 11, 13, val1);
CHECK_ADDRMAP_FIND (map2, array, 14, 19, nullptr);
/* Insert partially overlapping address range into mutable addrmap. */
- addrmap_set_empty (map, core_addr (&array[11]), core_addr (&array[13]),
- val2);
+ map->set_empty (core_addr (&array[11]), core_addr (&array[13]), val2);
CHECK_ADDRMAP_FIND (map, array, 0, 9, nullptr);
CHECK_ADDRMAP_FIND (map, array, 10, 12, val1);
CHECK_ADDRMAP_FIND (map, array, 13, 13, val2);
diff --git a/gdb/addrmap.h b/gdb/addrmap.h
index 7837c8521a1..948e9b07eaa 100644
--- a/gdb/addrmap.h
+++ b/gdb/addrmap.h
@@ -44,11 +44,61 @@ struct addrmap : public allocate_on_obstack
{
virtual ~addrmap () = default;
+ /* In the mutable address map MAP, associate the addresses from START
+ to END_INCLUSIVE that are currently associated with NULL with OBJ
+ instead. Addresses mapped to an object other than NULL are left
+ unchanged.
+
+ As the name suggests, END_INCLUSIVE is also mapped to OBJ. This
+ convention is unusual, but it allows callers to accurately specify
+ ranges that abut the top of the address space, and ranges that
+ cover the entire address space.
+
+ This operation seems a bit complicated for a primitive: if it's
+ needed, why not just have a simpler primitive operation that sets a
+ range to a value, wiping out whatever was there before, and then
+ let the caller construct more complicated operations from that,
+ along with some others for traversal?
+
+ It turns out this is the mutation operation we want to use all the
+ time, at least for now. Our immediate use for address maps is to
+ represent lexical blocks whose address ranges are not contiguous.
+ We walk the tree of lexical blocks present in the debug info, and
+ only create 'struct block' objects after we've traversed all a
+ block's children. If a lexical block declares no local variables
+ (and isn't the lexical block for a function's body), we omit it
+ from GDB's data structures entirely.
+
+ However, this means that we don't decide to create a block (and
+ thus record it in the address map) until after we've traversed its
+ children. If we do decide to create the block, we do so at a time
+ when all its children have already been recorded in the map. So
+ this operation --- change only those addresses left unset --- is
+ actually the operation we want to use every time.
+
+ It seems simpler to let the code which operates on the
+ representation directly deal with the hair of implementing these
+ semantics than to provide an interface which allows it to be
+ implemented efficiently, but doesn't reveal too much of the
+ representation. */
virtual void set_empty (CORE_ADDR start, CORE_ADDR end_inclusive,
void *obj) = 0;
+
+ /* Return the object associated with ADDR in MAP. */
virtual void *find (CORE_ADDR addr) = 0;
+
+ /* Create a fixed address map which is a copy of this mutable
+ address map. Allocate entries in OBSTACK. */
virtual struct addrmap *create_fixed (struct obstack *obstack) = 0;
+
+ /* Relocate all the addresses in MAP by OFFSET. (This can be applied
+ to either mutable or immutable maps.) */
virtual void relocate (CORE_ADDR offset) = 0;
+
+ /* Call FN for every address in MAP, following an in-order traversal.
+ If FN ever returns a non-zero value, the iteration ceases
+ immediately, and the value is returned. Otherwise, this function
+ returns 0. */
virtual int foreach (addrmap_foreach_fn fn) = 0;
};
@@ -156,65 +206,6 @@ struct addrmap_mutable : public addrmap
Allocate entries in OBSTACK. */
struct addrmap *addrmap_create_mutable (struct obstack *obstack);
-/* In the mutable address map MAP, associate the addresses from START
- to END_INCLUSIVE that are currently associated with NULL with OBJ
- instead. Addresses mapped to an object other than NULL are left
- unchanged.
-
- As the name suggests, END_INCLUSIVE is also mapped to OBJ. This
- convention is unusual, but it allows callers to accurately specify
- ranges that abut the top of the address space, and ranges that
- cover the entire address space.
-
- This operation seems a bit complicated for a primitive: if it's
- needed, why not just have a simpler primitive operation that sets a
- range to a value, wiping out whatever was there before, and then
- let the caller construct more complicated operations from that,
- along with some others for traversal?
-
- It turns out this is the mutation operation we want to use all the
- time, at least for now. Our immediate use for address maps is to
- represent lexical blocks whose address ranges are not contiguous.
- We walk the tree of lexical blocks present in the debug info, and
- only create 'struct block' objects after we've traversed all a
- block's children. If a lexical block declares no local variables
- (and isn't the lexical block for a function's body), we omit it
- from GDB's data structures entirely.
-
- However, this means that we don't decide to create a block (and
- thus record it in the address map) until after we've traversed its
- children. If we do decide to create the block, we do so at a time
- when all its children have already been recorded in the map. So
- this operation --- change only those addresses left unset --- is
- actually the operation we want to use every time.
-
- It seems simpler to let the code which operates on the
- representation directly deal with the hair of implementing these
- semantics than to provide an interface which allows it to be
- implemented efficiently, but doesn't reveal too much of the
- representation. */
-void addrmap_set_empty (struct addrmap *map,
- CORE_ADDR start, CORE_ADDR end_inclusive,
- void *obj);
-
-/* Return the object associated with ADDR in MAP. */
-void *addrmap_find (struct addrmap *map, CORE_ADDR addr);
-
-/* Create a fixed address map which is a copy of the mutable address
- map ORIGINAL. Allocate entries in OBSTACK. */
-struct addrmap *addrmap_create_fixed (struct addrmap *original,
- struct obstack *obstack);
-
-/* Relocate all the addresses in MAP by OFFSET. (This can be applied
- to either mutable or immutable maps.) */
-void addrmap_relocate (struct addrmap *map, CORE_ADDR offset);
-
-/* Call FN for every address in MAP, following an in-order traversal.
- If FN ever returns a non-zero value, the iteration ceases
- immediately, and the value is returned. Otherwise, this function
- returns 0. */
-int addrmap_foreach (struct addrmap *map, addrmap_foreach_fn fn);
-
/* Dump the addrmap to OUTFILE. If PAYLOAD is non-NULL, only dump any
components that map to PAYLOAD. (If PAYLOAD is NULL, the entire
map is dumped.) */
diff --git a/gdb/block.c b/gdb/block.c
index 3fe096db583..cd3a2c9619a 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -139,7 +139,7 @@ find_block_in_blockvector (const struct blockvector *bl, CORE_ADDR pc)
/* If we have an addrmap mapping code addresses to blocks, then use
that. */
if (BLOCKVECTOR_MAP (bl))
- return (const struct block *) addrmap_find (BLOCKVECTOR_MAP (bl), pc);
+ return (const struct block *) BLOCKVECTOR_MAP (bl)->find (pc);
/* Otherwise, use binary search to find the last block that starts
before PC.
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index 628903d674f..91c2f363054 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -419,7 +419,7 @@ buildsym_compunit::record_block_range (struct block *block,
if (m_pending_addrmap == nullptr)
m_pending_addrmap = addrmap_create_mutable (&m_pending_addrmap_obstack);
- addrmap_set_empty (m_pending_addrmap, start, end_inclusive, block);
+ m_pending_addrmap->set_empty (start, end_inclusive, block);
}
struct blockvector *
@@ -458,7 +458,7 @@ buildsym_compunit::make_blockvector ()
blockvector. */
if (m_pending_addrmap != nullptr && m_pending_addrmap_interesting)
BLOCKVECTOR_MAP (blockvector)
- = addrmap_create_fixed (m_pending_addrmap, &m_objfile->objfile_obstack);
+ = m_pending_addrmap->create_fixed (&m_objfile->objfile_obstack);
else
BLOCKVECTOR_MAP (blockvector) = 0;
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index 4b52eaf93d0..b4611d9e1f9 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -183,7 +183,7 @@ class cooked_index
void install_addrmap (addrmap *map)
{
gdb_assert (m_addrmap == nullptr);
- m_addrmap = addrmap_create_fixed (map, &m_storage);
+ m_addrmap = map->create_fixed (&m_storage);
}
friend class cooked_index_vector;
@@ -202,7 +202,7 @@ class cooked_index
found. */
dwarf2_per_cu_data *lookup (CORE_ADDR addr)
{
- return (dwarf2_per_cu_data *) addrmap_find (m_addrmap, addr);
+ return (dwarf2_per_cu_data *) m_addrmap->find (addr);
}
/* Create a new cooked_index_entry and register it with this object.
diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 58b0f0b98e3..2fd95d9951f 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -478,7 +478,7 @@ write_address_map (struct addrmap *addrmap, data_buf &addr_vec,
{
struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
- addrmap_foreach (addrmap, addrmap_index_data);
+ addrmap->foreach (addrmap_index_data);
/* It's highly unlikely the last entry (end address = 0xff...ff)
is valid, but we should still handle it.
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 6dcd446e5f4..488aff7c3d6 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2331,12 +2331,10 @@ create_addrmap_from_index (dwarf2_per_objfile *per_objfile,
lo = gdbarch_adjust_dwarf2_addr (gdbarch, lo + baseaddr) - baseaddr;
hi = gdbarch_adjust_dwarf2_addr (gdbarch, hi + baseaddr) - baseaddr;
- addrmap_set_empty (mutable_map, lo, hi - 1,
- per_bfd->get_cu (cu_index));
+ mutable_map->set_empty (lo, hi - 1, per_bfd->get_cu (cu_index));
}
- per_bfd->index_addrmap = addrmap_create_fixed (mutable_map,
- &per_bfd->obstack);
+ per_bfd->index_addrmap = mutable_map->create_fixed (&per_bfd->obstack);
}
/* Read the address map data from DWARF-5 .debug_aranges, and use it
@@ -2505,7 +2503,7 @@ read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
- baseaddr);
end = (gdbarch_adjust_dwarf2_addr (gdbarch, end + baseaddr)
- baseaddr);
- addrmap_set_empty (mutable_map, start, end - 1, per_cu);
+ mutable_map->set_empty (start, end - 1, per_cu);
}
per_cu->addresses_seen = true;
@@ -2527,8 +2525,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
addrmap *mutable_map = addrmap_create_mutable (&temp_obstack);
if (read_addrmap_from_aranges (per_objfile, section, mutable_map))
- per_bfd->index_addrmap = addrmap_create_fixed (mutable_map,
- &per_bfd->obstack);
+ per_bfd->index_addrmap = mutable_map->create_fixed (&per_bfd->obstack);
}
/* A helper function that reads the .gdb_index from BUFFER and fills
@@ -4292,8 +4289,7 @@ dwarf2_base_index_functions::find_pc_sect_compunit_symtab
CORE_ADDR baseaddr = objfile->text_section_offset ();
data = ((struct dwarf2_per_cu_data *)
- addrmap_find (per_objfile->per_bfd->index_addrmap,
- pc - baseaddr));
+ per_objfile->per_bfd->index_addrmap->find (pc - baseaddr));
if (!data)
return NULL;
@@ -12982,7 +12978,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
highpc = (gdbarch_adjust_dwarf2_addr (gdbarch,
range_end + baseaddr)
- baseaddr);
- addrmap_set_empty (map, lowpc, highpc - 1, datum);
+ map->set_empty (lowpc, highpc - 1, datum);
}
/* FIXME: This is recording everything as a low-high
@@ -17944,8 +17940,7 @@ cooked_indexer::check_bounds (cutu_reader *reader)
- baseaddr - 1);
/* Store the contiguous range if it is not empty; it can be
empty for CUs with no code. */
- addrmap_set_empty (m_index_storage->get_addrmap (), low, high,
- cu->per_cu);
+ m_index_storage->get_addrmap ()->set_empty (low, high, cu->per_cu);
cu->per_cu->addresses_seen = true;
}
@@ -18194,8 +18189,7 @@ cooked_indexer::scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
{
CORE_ADDR lookup = form_addr (origin_offset, origin_is_dwz);
*parent_entry
- = (cooked_index_entry *) addrmap_find (m_die_range_map,
- lookup);
+ = (cooked_index_entry *) m_die_range_map->find (lookup);
}
unsigned int bytes_read;
@@ -18235,8 +18229,8 @@ cooked_indexer::scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
CORE_ADDR hi
= (gdbarch_adjust_dwarf2_addr (gdbarch, *high_pc + baseaddr)
- baseaddr);
- addrmap_set_empty (m_index_storage->get_addrmap (), lo, hi - 1,
- scanning_per_cu);
+ m_index_storage->get_addrmap ()->set_empty (lo, hi - 1,
+ scanning_per_cu);
}
}
@@ -18312,7 +18306,7 @@ cooked_indexer::recurse (cutu_reader *reader,
reader->cu->per_cu->is_dwz);
CORE_ADDR end = form_addr (sect_offset (info_ptr - 1 - reader->buffer),
reader->cu->per_cu->is_dwz);
- addrmap_set_empty (m_die_range_map, start, end, (void *) parent_entry);
+ m_die_range_map->set_empty (start, end, (void *) parent_entry);
}
return info_ptr;
@@ -18478,7 +18472,7 @@ cooked_indexer::make_index (cutu_reader *reader)
{
CORE_ADDR key = form_addr (entry.die_offset, m_per_cu->is_dwz);
cooked_index_entry *parent
- = (cooked_index_entry *) addrmap_find (m_die_range_map, key);
+ = (cooked_index_entry *) m_die_range_map->find (key);
m_index_storage->add (entry.die_offset, entry.tag, entry.flags,
entry.name, parent, m_per_cu);
}
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index bcdf36cd067..b0a276dbe18 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -289,8 +289,7 @@ block_starting_point_at (CORE_ADDR pc, const struct block *block)
if (BLOCKVECTOR_MAP (bv) == NULL)
return 0;
- new_block = (const struct block *) addrmap_find (BLOCKVECTOR_MAP (bv),
- pc - 1);
+ new_block = (const struct block *) BLOCKVECTOR_MAP (bv)->find (pc - 1);
if (new_block == NULL)
return 1;
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 0c71e0bd6a9..e1f33b32ccb 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -668,7 +668,7 @@ objfile_relocate1 (struct objfile *objfile,
int block_line_section = cust->block_line_section ();
if (BLOCKVECTOR_MAP (bv))
- addrmap_relocate (BLOCKVECTOR_MAP (bv), delta[block_line_section]);
+ BLOCKVECTOR_MAP (bv)->relocate (delta[block_line_section]);
for (int i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
{
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 5d9949bca1d..8b36a18a0ff 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -193,8 +193,7 @@ psymbol_functions::find_pc_sect_psymtab (struct objfile *objfile,
struct partial_symtab *pst
= ((struct partial_symtab *)
- addrmap_find (m_partial_symtabs->psymtabs_addrmap,
- pc - baseaddr));
+ m_partial_symtabs->psymtabs_addrmap->find (pc - baseaddr));
if (pst != NULL)
{
/* FIXME: addrmaps currently do not handle overlayed sections,
diff --git a/gdb/symtab.c b/gdb/symtab.c
index a75492603b8..20cc40b7dd1 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2990,7 +2990,7 @@ find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
if (BLOCKVECTOR_MAP (bv))
{
- if (addrmap_find (BLOCKVECTOR_MAP (bv), pc) == nullptr)
+ if (BLOCKVECTOR_MAP (bv)->find (pc) == nullptr)
continue;
return cust;
--
2.34.1
next prev parent reply other threads:[~2022-04-16 16:58 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-04-16 16:58 [PATCH 0/9] C++-ify addrmap Tom Tromey
2022-04-16 16:58 ` [PATCH 1/9] Use inheritance for addrmap Tom Tromey
2022-04-16 16:58 ` [PATCH 2/9] Privacy for addrmap_fixed Tom Tromey
2022-04-16 16:58 ` [PATCH 3/9] Privacy for addrmap_mutable Tom Tromey
2022-04-16 16:58 ` [PATCH 4/9] Move addrmap classes to addrmap.h Tom Tromey
2022-04-16 16:58 ` Tom Tromey [this message]
2022-04-16 16:58 ` [PATCH 6/9] Remove addrmap_create_mutable Tom Tromey
2022-04-16 16:58 ` [PATCH 7/9] Remove addrmap::create_fixed Tom Tromey
2022-04-16 16:58 ` [PATCH 8/9] Use malloc for mutable addrmaps Tom Tromey
2022-04-16 16:58 ` [PATCH 9/9] Remove psymtab_addrmap Tom Tromey
2022-06-12 16:48 ` [PATCH 0/9] C++-ify addrmap Tom Tromey
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=20220416165821.3648899-6-tom@tromey.com \
--to=tom@tromey.com \
--cc=gdb-patches@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).