From: Zoran Zaric <Zoran.Zaric@amd.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 23/43] Add read method to location description classes
Date: Mon, 1 Mar 2021 14:46:00 +0000 [thread overview]
Message-ID: <20210301144620.103016-24-Zoran.Zaric@amd.com> (raw)
In-Reply-To: <20210301144620.103016-1-Zoran.Zaric@amd.com>
After adding the interface for register and memory location access, a
new method for reading from any location derived from a dwarf_location
class, can now be defined.
In the case of implicit pointer location description the existing
indirect_synthetic_pointer interface requiers a type of the pointer
to be specified, so for a generic read interface the only type that
makes sense is the DWARF generic type. This means that the existing
address_type method of a dwarf_expr_context class needs to be exposed
outside of that class.
gdb/ChangeLog:
* dwarf2/expr.c (dwarf_location::read): New method.
(dwarf_undefined::read): New method.
(dwarf_memory::read): New method.
(dwarf_register::read): New method.
(dwarf_implicit::read): New method.
(dwarf_implicit_pointer::read): New method.
(dwarf_composite::read): New method.
(dwarf_expr_context::address_type): Change to use the new
address_type function.
(address_type): New function.
---
gdb/dwarf2/expr.c | 305 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 283 insertions(+), 22 deletions(-)
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 69be36fcf2d..35b2efa6cb5 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -285,6 +285,37 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
length, buffer);
}
+/* Return the type used for DWARF operations where the type is
+ generic in the DWARF spec, the ARCH is a target architecture.
+ of the type and ADDR_SIZE is expected size of the address.
+ Only certain sizes are supported. */
+
+static struct type *
+address_type (struct gdbarch *gdbarch, int addr_size)
+{
+ struct dwarf_gdbarch_types *types
+ = (struct dwarf_gdbarch_types *) gdbarch_data (gdbarch,
+ dwarf_arch_cookie);
+ int ndx;
+
+ if (addr_size == 2)
+ ndx = 0;
+ else if (addr_size == 4)
+ ndx = 1;
+ else if (addr_size == 8)
+ ndx = 2;
+ else
+ error (_("Unsupported address size in DWARF expressions: %d bits"),
+ 8 * addr_size);
+
+ if (types->dw_types[ndx] == NULL)
+ types->dw_types[ndx]
+ = arch_integer_type (gdbarch, HOST_CHAR_BIT * addr_size,
+ 0, "<signed DWARF address type>");
+
+ return types->dw_types[ndx];
+}
+
class dwarf_location;
class dwarf_memory;
class dwarf_value;
@@ -369,6 +400,27 @@ class dwarf_location : public dwarf_entry
return std::shared_ptr<dwarf_value> (nullptr);
}
+ /* Read contents from the descripbed location.
+
+ The read operation is performed in the context of a FRAME.
+ BIT_SIZE is the number of bits to read. The data read is copied
+ to the caller-managed buffer BUF. BIG_ENDIAN defines the
+ endianness of the target. BITS_TO_SKIP is a bit offset into the
+ location and BUF_BIT_OFFSET is buffer BUF's bit offset.
+ LOCATION_BIT_LIMIT is a maximum number of bits that location can
+ hold, where value zero signifies that there is no such
+ restriction.
+
+ Note that some location types can be read without a FRAME context.
+
+ If the location is optimized out or unavailable, the OPTIMIZED and
+ UNAVAILABLE outputs are set accordingly. */
+ virtual void read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized,
+ int *unavailable) const = 0;
+
protected:
/* Architecture of the location. */
struct gdbarch *m_arch;
@@ -475,6 +527,14 @@ class dwarf_undefined : public dwarf_location
LONGEST bit_suboffset = 0)
: dwarf_location (arch, offset, bit_suboffset)
{}
+
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const override
+ {
+ *unavailable = 0;
+ *optimized = 1;
+ }
};
class dwarf_memory : public dwarf_location
@@ -493,6 +553,11 @@ class dwarf_memory : public dwarf_location
std::shared_ptr<dwarf_value> to_value (struct type *type) override;
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip,
+ size_t location_bit_limit, bool big_endian,
+ int *optimized, int *unavailable) const override;
+
private:
/* True if the location belongs to a stack memory region. */
bool m_stack;
@@ -504,6 +569,46 @@ dwarf_memory::to_value (struct type *type)
return std::make_shared<dwarf_value> (m_offset, type);
}
+void
+dwarf_memory::read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const
+{
+ LONGEST total_bits_to_skip = bits_to_skip;
+ CORE_ADDR start_address
+ = m_offset + (m_bit_suboffset + total_bits_to_skip) / HOST_CHAR_BIT;
+ gdb::byte_vector temp_buf;
+
+ *optimized = 0;
+ total_bits_to_skip += m_bit_suboffset;
+
+ if (total_bits_to_skip % HOST_CHAR_BIT == 0
+ && bit_size % HOST_CHAR_BIT == 0
+ && buf_bit_offset % HOST_CHAR_BIT == 0)
+ {
+ /* Everything is byte-aligned, no buffer needed. */
+ read_from_memory (start_address,
+ buf + buf_bit_offset / HOST_CHAR_BIT,
+ bit_size / HOST_CHAR_BIT, m_stack, unavailable);
+ }
+ else
+ {
+ LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+ temp_buf.resize (this_size);
+
+ /* Can only read from memory on byte granularity so an
+ additional buffer is required. */
+ read_from_memory (start_address, temp_buf.data (), this_size,
+ m_stack, unavailable);
+
+ if (!*unavailable)
+ copy_bitwise (buf, buf_bit_offset, temp_buf.data (),
+ total_bits_to_skip % HOST_CHAR_BIT,
+ bit_size, big_endian);
+ }
+}
+
/* Register location description entry. */
class dwarf_register : public dwarf_location
@@ -515,11 +620,55 @@ class dwarf_register : public dwarf_location
m_regnum (regnum)
{}
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const override;
+
private:
/* DWARF register number. */
unsigned int m_regnum;
};
+void
+dwarf_register::read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const
+{
+ LONGEST total_bits_to_skip = bits_to_skip;
+ size_t read_bit_limit = location_bit_limit;
+ int reg = dwarf_reg_to_regnum_or_error (m_arch, m_regnum);
+ ULONGEST reg_bits = HOST_CHAR_BIT * register_size (m_arch, reg);
+ gdb::byte_vector temp_buf;
+
+ if (big_endian)
+ {
+ if (!read_bit_limit || reg_bits <= read_bit_limit)
+ read_bit_limit = bit_size;
+
+ total_bits_to_skip += reg_bits - (m_offset * HOST_CHAR_BIT
+ + m_bit_suboffset + read_bit_limit);
+ }
+ else
+ total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+ LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+ temp_buf.resize (this_size);
+
+ if (frame == NULL)
+ internal_error (__FILE__, __LINE__, _("invalid frame information"));
+
+ /* Can only read from a register on byte granularity so an
+ additional buffer is required. */
+ read_from_register (frame, reg, total_bits_to_skip / HOST_CHAR_BIT,
+ temp_buf, optimized, unavailable);
+
+ /* Only copy data if valid. */
+ if (!*optimized && !*unavailable)
+ copy_bitwise (buf, buf_bit_offset, temp_buf.data (),
+ total_bits_to_skip % HOST_CHAR_BIT, bit_size, big_endian);
+}
+
/* Implicit location description entry. Describes a location
description not found on the target but instead saved in a
gdb-allocated buffer. */
@@ -539,6 +688,10 @@ class dwarf_implicit : public dwarf_location
m_byte_order = byte_order;
}
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const override;
+
private:
/* Implicit location contents as a stream of bytes in target byte-order. */
gdb::unique_xmalloc_ptr<gdb_byte> m_contents;
@@ -550,6 +703,45 @@ class dwarf_implicit : public dwarf_location
enum bfd_endian m_byte_order;
};
+void
+dwarf_implicit::read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const
+{
+ ULONGEST implicit_bit_size = HOST_CHAR_BIT * m_size;
+ LONGEST total_bits_to_skip = bits_to_skip;
+ size_t read_bit_limit = location_bit_limit;
+
+ *optimized = 0;
+ *unavailable = 0;
+
+ /* Cut off at the end of the implicit value. */
+ if (m_byte_order == BFD_ENDIAN_BIG)
+ {
+ if (!read_bit_limit || read_bit_limit > implicit_bit_size)
+ read_bit_limit = bit_size;
+
+ total_bits_to_skip
+ += implicit_bit_size - (m_offset * HOST_CHAR_BIT
+ + m_bit_suboffset + read_bit_limit);
+ }
+ else
+ total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+ if (total_bits_to_skip >= implicit_bit_size)
+ {
+ (*unavailable) = 1;
+ return;
+ }
+
+ if (bit_size > implicit_bit_size - total_bits_to_skip)
+ bit_size = implicit_bit_size - total_bits_to_skip;
+
+ copy_bitwise (buf, buf_bit_offset, m_contents.get (),
+ total_bits_to_skip, bit_size, big_endian);
+}
+
/* Implicit pointer location description entry. */
class dwarf_implicit_pointer : public dwarf_location
@@ -565,6 +757,10 @@ class dwarf_implicit_pointer : public dwarf_location
m_addr_size (addr_size), m_die_offset (die_offset)
{}
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const override;
+
private:
/* Per object file data of the implicit pointer. */
dwarf2_per_objfile *m_per_objfile;
@@ -579,6 +775,44 @@ class dwarf_implicit_pointer : public dwarf_location
sect_offset m_die_offset;
};
+void
+dwarf_implicit_pointer::read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized,
+ int *unavailable) const
+{
+ struct frame_info *actual_frame = frame;
+ LONGEST total_bits_to_skip = bits_to_skip + m_bit_suboffset;
+
+ if (actual_frame == nullptr)
+ actual_frame = get_selected_frame (_("No frame selected."));
+
+ struct type *type
+ = address_type (get_frame_arch (actual_frame), m_addr_size);
+
+ struct value *value
+ = indirect_synthetic_pointer (m_die_offset, m_offset, m_per_cu,
+ m_per_objfile, actual_frame, type);
+
+ gdb_byte *value_contents
+ = value_contents_raw (value) + total_bits_to_skip / HOST_CHAR_BIT;
+
+ if (total_bits_to_skip % HOST_CHAR_BIT == 0
+ && bit_size % HOST_CHAR_BIT == 0
+ && buf_bit_offset % HOST_CHAR_BIT == 0)
+ {
+ memcpy (buf + buf_bit_offset / HOST_CHAR_BIT,
+ value_contents, bit_size / HOST_CHAR_BIT);
+ }
+ else
+ {
+ copy_bitwise (buf, buf_bit_offset, value_contents,
+ total_bits_to_skip % HOST_CHAR_BIT,
+ bit_size, big_endian);
+ }
+}
+
/* Composite location description entry. */
class dwarf_composite : public dwarf_location
@@ -595,6 +829,10 @@ class dwarf_composite : public dwarf_location
m_pieces.emplace_back (location, bit_size);
}
+ void read (struct frame_info *frame, gdb_byte *buf, int buf_bit_offset,
+ size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const override;
+
private:
/* Composite piece that contains a piece location
description and it's size. */
@@ -617,6 +855,50 @@ class dwarf_composite : public dwarf_location
std::vector<struct piece> m_pieces;
};
+void
+dwarf_composite::read (struct frame_info *frame, gdb_byte *buf,
+ int buf_bit_offset, size_t bit_size,
+ LONGEST bits_to_skip, size_t location_bit_limit,
+ bool big_endian, int *optimized, int *unavailable) const
+{
+ unsigned int pieces_num = m_pieces.size ();
+ LONGEST total_bits_to_skip = bits_to_skip;
+ unsigned int i;
+
+ total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+ /* Skip pieces covered by the read offset. */
+ for (i = 0; i < pieces_num; i++)
+ {
+ LONGEST piece_bit_size = m_pieces[i].m_size;
+
+ if (total_bits_to_skip < piece_bit_size)
+ break;
+
+ total_bits_to_skip -= piece_bit_size;
+ }
+
+ for (; i < pieces_num; i++)
+ {
+ LONGEST piece_bit_size = m_pieces[i].m_size;
+ LONGEST actual_bit_size = piece_bit_size;
+
+ if (actual_bit_size > bit_size)
+ actual_bit_size = bit_size;
+
+ m_pieces[i].m_location->read (frame, buf, buf_bit_offset,
+ actual_bit_size, total_bits_to_skip,
+ piece_bit_size, big_endian,
+ optimized, unavailable);
+
+ if (bit_size == actual_bit_size || *optimized || *unavailable)
+ break;
+
+ buf_bit_offset += actual_bit_size;
+ bit_size -= actual_bit_size;
+ }
+}
+
struct piece_closure
{
/* Reference count. */
@@ -1198,28 +1480,7 @@ sect_variable_value (sect_offset sect_off,
struct type *
dwarf_expr_context::address_type () const
{
- struct dwarf_gdbarch_types *types
- = (struct dwarf_gdbarch_types *) gdbarch_data (this->gdbarch,
- dwarf_arch_cookie);
- int ndx;
-
- if (this->addr_size == 2)
- ndx = 0;
- else if (this->addr_size == 4)
- ndx = 1;
- else if (this->addr_size == 8)
- ndx = 2;
- else
- error (_("Unsupported address size in DWARF expressions: %d bits"),
- 8 * this->addr_size);
-
- if (types->dw_types[ndx] == NULL)
- types->dw_types[ndx]
- = arch_integer_type (this->gdbarch,
- 8 * this->addr_size,
- 0, "<signed DWARF address type>");
-
- return types->dw_types[ndx];
+ return ::address_type (this->gdbarch, this->addr_size);
}
/* Create a new context for the expression evaluator. */
--
2.17.1
next prev parent reply other threads:[~2021-03-01 14:47 UTC|newest]
Thread overview: 86+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-01 14:45 [PATCH 00/43 V2] Allow location description on the DWARF stack Zoran Zaric
2021-03-01 14:45 ` [PATCH 01/43] Replace the symbol needs evaluator with a parser Zoran Zaric
2021-04-27 1:20 ` Simon Marchi
2021-04-28 10:17 ` Zoran Zaric
2021-04-28 14:08 ` Simon Marchi
2021-04-28 15:02 ` Zoran Zaric
2021-04-28 15:31 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 02/43] Cleanup of the dwarf_expr_context constructor Zoran Zaric
2021-04-27 1:23 ` Simon Marchi
2021-04-28 10:19 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 03/43] Move frame context info to dwarf_expr_context Zoran Zaric
2021-04-27 2:19 ` Simon Marchi
2021-04-28 10:51 ` Zoran Zaric
2021-04-28 14:14 ` Simon Marchi
2021-04-28 15:55 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 04/43] Remove get_frame_cfa from dwarf_expr_context Zoran Zaric
2021-03-01 14:45 ` [PATCH 05/43] Move compilation unit info to dwarf_expr_context Zoran Zaric
2021-04-27 2:58 ` Simon Marchi
2021-04-28 11:28 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 06/43] Move dwarf_call " Zoran Zaric
2021-03-01 14:45 ` [PATCH 07/43] Move get_object_address " Zoran Zaric
2021-04-27 3:12 ` Simon Marchi
2021-04-28 11:34 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 08/43] Move read_mem " Zoran Zaric
2021-03-01 14:45 ` [PATCH 09/43] Move push_dwarf_reg_entry_value to expr.c Zoran Zaric
2021-04-27 3:56 ` Simon Marchi
2021-04-28 11:36 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 10/43] Inline get_reg_value method of dwarf_expr_context Zoran Zaric
2021-03-01 14:45 ` [PATCH 11/43] Remove empty frame and full evaluators Zoran Zaric
2021-03-01 14:45 ` [PATCH 12/43] Merge evaluate_for_locexpr_baton evaluator Zoran Zaric
2021-04-28 1:33 ` Simon Marchi
2021-04-28 11:39 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 13/43] Move piece_closure and its support to expr.c Zoran Zaric
2021-04-28 1:56 ` Simon Marchi
2021-04-28 11:40 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 14/43] Make value_copy also copy the stack data member Zoran Zaric
2021-04-28 2:01 ` Simon Marchi
2021-04-28 11:43 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 15/43] Make DWARF evaluator return a single struct value Zoran Zaric
2021-04-28 2:21 ` Simon Marchi
2021-04-28 11:47 ` Zoran Zaric
2021-04-28 14:24 ` Simon Marchi
2021-03-01 14:45 ` [PATCH 16/43] Simplify dwarf_expr_context class interface Zoran Zaric
2021-04-28 2:45 ` Simon Marchi
2021-04-28 13:15 ` Zoran Zaric
2021-04-28 14:41 ` Simon Marchi
2021-04-28 15:39 ` Zoran Zaric
2021-04-28 19:19 ` Simon Marchi
2021-04-29 15:49 ` Simon Marchi
2021-04-29 15:55 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 17/43] Add as_lval argument to expression evaluator Zoran Zaric
2021-04-28 3:04 ` Simon Marchi
2021-04-28 13:16 ` Zoran Zaric
2021-04-28 3:30 ` Simon Marchi
2021-03-01 14:45 ` [PATCH 18/43] Add new register access interface to expr.c Zoran Zaric
2021-03-08 23:52 ` Lancelot SIX
2021-04-28 3:25 ` Simon Marchi
2021-04-28 13:29 ` Zoran Zaric
2021-04-28 14:48 ` Simon Marchi
2021-04-28 15:42 ` Zoran Zaric
2021-03-01 14:45 ` [PATCH 19/43] Add new memory " Zoran Zaric
2021-04-30 21:24 ` Simon Marchi
2021-03-01 14:45 ` [PATCH 20/43] Add new classes that model DWARF stack element Zoran Zaric
2021-03-01 14:45 ` [PATCH 21/43] Add to_location method to DWARF entry classes Zoran Zaric
2021-03-01 14:45 ` [PATCH 22/43] Add to_value " Zoran Zaric
2021-03-01 14:46 ` Zoran Zaric [this message]
2021-03-01 14:46 ` [PATCH 24/43] Add write method to location description classes Zoran Zaric
2021-03-01 14:46 ` [PATCH 25/43] Add deref " Zoran Zaric
2021-03-01 14:46 ` [PATCH 26/43] Add read_from_gdb_value method to dwarf_location Zoran Zaric
2021-03-01 14:46 ` [PATCH 27/43] Add write_to_gdb_value " Zoran Zaric
2021-03-01 14:46 ` [PATCH 28/43] Add is_implicit_ptr_at " Zoran Zaric
2021-03-01 14:46 ` [PATCH 29/43] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
2021-03-01 14:46 ` [PATCH 30/43] Add new computed struct value callback interface Zoran Zaric
2021-03-01 14:46 ` [PATCH 31/43] Add to_gdb_value method to DWARF entry class Zoran Zaric
2021-03-01 14:46 ` [PATCH 32/43] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
2021-03-01 14:46 ` [PATCH 33/43] Remove old computed struct value callbacks Zoran Zaric
2021-03-01 14:46 ` [PATCH 34/43] Comments cleanup between expr.h and expr.c Zoran Zaric
2021-03-01 14:46 ` [PATCH 35/43] Remove dwarf_expr_context from expr.h interface Zoran Zaric
2021-03-01 14:46 ` [PATCH 36/43] Move read_addr_from_reg function to frame.c Zoran Zaric
2021-03-01 14:46 ` [PATCH 37/43] Add frame info check to DW_OP_reg operations Zoran Zaric
2021-03-01 14:46 ` [PATCH 38/43] Remove DWARF expression composition check Zoran Zaric
2021-03-01 14:46 ` [PATCH 39/43] Change back the symbol needs to use the evaluator Zoran Zaric
2021-03-01 14:46 ` [PATCH 40/43] Add support for any location description in CFI Zoran Zaric
2021-03-01 14:46 ` [PATCH 41/43] Add DWARF operations for byte and bit offset Zoran Zaric
2021-03-01 14:46 ` [PATCH 42/43] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
2021-03-01 14:46 ` [PATCH 43/43] Add support for nested composite locations Zoran Zaric
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=20210301144620.103016-24-Zoran.Zaric@amd.com \
--to=zoran.zaric@amd.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).