From: takahiro.akashi@linaro.org (AKASHI Takahiro)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v5 4/6] arm64: insn: add instruction decoders for ldp/stp and add/sub
Date: Wed, 11 Nov 2015 13:54:37 +0900 [thread overview]
Message-ID: <5642CA0D.9080708@linaro.org> (raw)
In-Reply-To: <999DB062-D4C8-4050-ADF7-9C6CEEC0BF73@gmail.com>
On 11/10/2015 10:40 PM, Jungseok Lee wrote:
> On Nov 6, 2015, at 3:44 PM, AKASHI Takahiro wrote:
>> A function prologue analyzer is a requisite for implementing stack tracer
>> and getting better views of stack usages on arm64.
>> To implement a function prologue analyzer, we have to be able to decode,
>> at least, stp, add, sub and mov instructions.
>>
>> This patch adds decoders for those instructions, that are used solely
>> by stack tracer for now, but generic enough for other uses.
>>
>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>> ---
>> arch/arm64/include/asm/insn.h | 18 ++++++++
>> arch/arm64/kernel/insn.c | 102 +++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 120 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
>> index 30e50eb..8d5c538 100644
>> --- a/arch/arm64/include/asm/insn.h
>> +++ b/arch/arm64/include/asm/insn.h
>> @@ -165,6 +165,8 @@ enum aarch64_insn_ldst_type {
>> AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
>> AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
>> AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
>> + AARCH64_INSN_LDST_LOAD_PAIR,
>> + AARCH64_INSN_LDST_STORE_PAIR,
>> };
>>
>> enum aarch64_insn_adsb_type {
>> @@ -225,6 +227,8 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
>>
>> __AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
>> __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
>> +__AARCH64_INSN_FUNCS(stp, 0x7FC00000, 0x29000000)
>> +__AARCH64_INSN_FUNCS(ldp, 0x7FC00000, 0x29400000)
>> __AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
>> __AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
>> __AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000)
>> @@ -277,6 +281,7 @@ __AARCH64_INSN_FUNCS(hint, 0xFFFFF01F, 0xD503201F)
>> __AARCH64_INSN_FUNCS(br, 0xFFFFFC1F, 0xD61F0000)
>> __AARCH64_INSN_FUNCS(blr, 0xFFFFFC1F, 0xD63F0000)
>> __AARCH64_INSN_FUNCS(ret, 0xFFFFFC1F, 0xD65F0000)
>> +__AARCH64_INSN_FUNCS(eret, 0xFFFFFFFF, 0xD69F00E0)
>
> According to C4.2.7, the third argument looks like 0xD69F03E0. Rn field is 11111
> in case of eret.
Thanks. Fix it (c3.2.7 though).
-Takahiro AKASHI
> Best Regards
> Jungseok Lee
>
>> #undef __AARCH64_INSN_FUNCS
>>
>> @@ -370,6 +375,19 @@ bool aarch32_insn_is_wide(u32 insn);
>> u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
>> u32 aarch32_insn_mcr_extract_opc2(u32 insn);
>> u32 aarch32_insn_mcr_extract_crm(u32 insn);
>> +int aarch64_insn_decode_add_sub_imm(u32 insn,
>> + enum aarch64_insn_register *dst,
>> + enum aarch64_insn_register *src,
>> + int *imm,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_adsb_type *type);
>> +int aarch64_insn_decode_load_store_pair(u32 insn,
>> + enum aarch64_insn_register *reg1,
>> + enum aarch64_insn_register *reg2,
>> + enum aarch64_insn_register *base,
>> + int *offset,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_ldst_type *type);
>> #endif /* __ASSEMBLY__ */
>>
>> #endif /* __ASM_INSN_H */
>> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
>> index c08b9ad..b56a66c 100644
>> --- a/arch/arm64/kernel/insn.c
>> +++ b/arch/arm64/kernel/insn.c
>> @@ -33,6 +33,7 @@
>> #include <asm/insn.h>
>>
>> #define AARCH64_INSN_SF_BIT BIT(31)
>> +#define AARCH64_INSN_S_BIT BIT(29)
>> #define AARCH64_INSN_N_BIT BIT(22)
>>
>> static int aarch64_insn_encoding_class[] = {
>> @@ -1141,3 +1142,104 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn)
>> {
>> return insn & CRM_MASK;
>> }
>> +
>> +enum aarch64_insn_register aarch64_insn_extract_reg_num(u32 insn,
>> + enum aarch64_insn_register_type type)
>> +{
>> + int shift;
>> +
>> + switch (type) {
>> + case AARCH64_INSN_REGTYPE_RT:
>> + case AARCH64_INSN_REGTYPE_RD:
>> + shift = 0;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RN:
>> + shift = 5;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RT2:
>> + case AARCH64_INSN_REGTYPE_RA:
>> + shift = 10;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RM:
>> + shift = 16;
>> + break;
>> + default:
>> + pr_err("%s: unknown register type decoding %d\n", __func__,
>> + type);
>> + return ~0L;
>> + }
>> +
>> + return (insn & (GENMASK(4, 0) << shift)) >> shift;
>> +}
>> +
>> +int aarch64_insn_decode_add_sub_imm(u32 insn,
>> + enum aarch64_insn_register *dst,
>> + enum aarch64_insn_register *src,
>> + int *imm,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_adsb_type *type)
>> +{
>> + if (aarch64_insn_is_add_imm(insn))
>> + *type = ((insn) & AARCH64_INSN_S_BIT) ?
>> + AARCH64_INSN_ADSB_ADD_SETFLAGS :
>> + AARCH64_INSN_ADSB_ADD;
>> + else if (aarch64_insn_is_sub_imm(insn))
>> + *type = ((insn) & AARCH64_INSN_S_BIT) ?
>> + AARCH64_INSN_ADSB_SUB_SETFLAGS :
>> + AARCH64_INSN_ADSB_SUB;
>> + else
>> + return 0;
>> +
>> + *variant = (insn & AARCH64_INSN_SF_BIT) ? AARCH64_INSN_VARIANT_64BIT :
>> + AARCH64_INSN_VARIANT_32BIT;
>> +
>> + *dst = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RD);
>> +
>> + *src = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RN);
>> +
>> + /* TODO: ignore shilft field[23:22] */
>> + *imm = (int)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_12, insn);
>> +
>> + return 1;
>> +}
>> +
>> +int aarch64_insn_decode_load_store_pair(u32 insn,
>> + enum aarch64_insn_register *reg1,
>> + enum aarch64_insn_register *reg2,
>> + enum aarch64_insn_register *base,
>> + int *offset,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_ldst_type *type)
>> +{
>> + int imm;
>> +
>> + if (aarch64_insn_is_stp(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR;
>> + else if (aarch64_insn_is_stp_post(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX;
>> + else if (aarch64_insn_is_stp_pre(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX;
>> + else if (aarch64_insn_is_ldp(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR;
>> + else if (aarch64_insn_is_ldp_post(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX;
>> + else if (aarch64_insn_is_ldp_pre(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX;
>> + else
>> + return 0;
>> +
>> + *variant = (insn & AARCH64_INSN_S_BIT) ? AARCH64_INSN_VARIANT_64BIT :
>> + AARCH64_INSN_VARIANT_32BIT;
>> +
>> + *reg1 = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RT);
>> +
>> + *reg2 = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RT2);
>> +
>> + *base = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RN);
>> +
>> + imm = (int)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_7, insn);
>> + asm("sbfm %0, %0, 0, 6" : "+r" (imm));
>> + *offset = imm * 8;
>> +
>> + return 1;
>> +}
>> --
>> 1.7.9.5
>>
>
WARNING: multiple messages have this Message-ID (diff)
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
To: Jungseok Lee <jungseoklee85@gmail.com>
Cc: catalin.marinas@arm.com, will.deacon@arm.com,
rostedt@goodmis.org, broonie@kernel.org, david.griego@linaro.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 4/6] arm64: insn: add instruction decoders for ldp/stp and add/sub
Date: Wed, 11 Nov 2015 13:54:37 +0900 [thread overview]
Message-ID: <5642CA0D.9080708@linaro.org> (raw)
In-Reply-To: <999DB062-D4C8-4050-ADF7-9C6CEEC0BF73@gmail.com>
On 11/10/2015 10:40 PM, Jungseok Lee wrote:
> On Nov 6, 2015, at 3:44 PM, AKASHI Takahiro wrote:
>> A function prologue analyzer is a requisite for implementing stack tracer
>> and getting better views of stack usages on arm64.
>> To implement a function prologue analyzer, we have to be able to decode,
>> at least, stp, add, sub and mov instructions.
>>
>> This patch adds decoders for those instructions, that are used solely
>> by stack tracer for now, but generic enough for other uses.
>>
>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
>> ---
>> arch/arm64/include/asm/insn.h | 18 ++++++++
>> arch/arm64/kernel/insn.c | 102 +++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 120 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
>> index 30e50eb..8d5c538 100644
>> --- a/arch/arm64/include/asm/insn.h
>> +++ b/arch/arm64/include/asm/insn.h
>> @@ -165,6 +165,8 @@ enum aarch64_insn_ldst_type {
>> AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX,
>> AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX,
>> AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX,
>> + AARCH64_INSN_LDST_LOAD_PAIR,
>> + AARCH64_INSN_LDST_STORE_PAIR,
>> };
>>
>> enum aarch64_insn_adsb_type {
>> @@ -225,6 +227,8 @@ static __always_inline u32 aarch64_insn_get_##abbr##_value(void) \
>>
>> __AARCH64_INSN_FUNCS(str_reg, 0x3FE0EC00, 0x38206800)
>> __AARCH64_INSN_FUNCS(ldr_reg, 0x3FE0EC00, 0x38606800)
>> +__AARCH64_INSN_FUNCS(stp, 0x7FC00000, 0x29000000)
>> +__AARCH64_INSN_FUNCS(ldp, 0x7FC00000, 0x29400000)
>> __AARCH64_INSN_FUNCS(stp_post, 0x7FC00000, 0x28800000)
>> __AARCH64_INSN_FUNCS(ldp_post, 0x7FC00000, 0x28C00000)
>> __AARCH64_INSN_FUNCS(stp_pre, 0x7FC00000, 0x29800000)
>> @@ -277,6 +281,7 @@ __AARCH64_INSN_FUNCS(hint, 0xFFFFF01F, 0xD503201F)
>> __AARCH64_INSN_FUNCS(br, 0xFFFFFC1F, 0xD61F0000)
>> __AARCH64_INSN_FUNCS(blr, 0xFFFFFC1F, 0xD63F0000)
>> __AARCH64_INSN_FUNCS(ret, 0xFFFFFC1F, 0xD65F0000)
>> +__AARCH64_INSN_FUNCS(eret, 0xFFFFFFFF, 0xD69F00E0)
>
> According to C4.2.7, the third argument looks like 0xD69F03E0. Rn field is 11111
> in case of eret.
Thanks. Fix it (c3.2.7 though).
-Takahiro AKASHI
> Best Regards
> Jungseok Lee
>
>> #undef __AARCH64_INSN_FUNCS
>>
>> @@ -370,6 +375,19 @@ bool aarch32_insn_is_wide(u32 insn);
>> u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
>> u32 aarch32_insn_mcr_extract_opc2(u32 insn);
>> u32 aarch32_insn_mcr_extract_crm(u32 insn);
>> +int aarch64_insn_decode_add_sub_imm(u32 insn,
>> + enum aarch64_insn_register *dst,
>> + enum aarch64_insn_register *src,
>> + int *imm,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_adsb_type *type);
>> +int aarch64_insn_decode_load_store_pair(u32 insn,
>> + enum aarch64_insn_register *reg1,
>> + enum aarch64_insn_register *reg2,
>> + enum aarch64_insn_register *base,
>> + int *offset,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_ldst_type *type);
>> #endif /* __ASSEMBLY__ */
>>
>> #endif /* __ASM_INSN_H */
>> diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
>> index c08b9ad..b56a66c 100644
>> --- a/arch/arm64/kernel/insn.c
>> +++ b/arch/arm64/kernel/insn.c
>> @@ -33,6 +33,7 @@
>> #include <asm/insn.h>
>>
>> #define AARCH64_INSN_SF_BIT BIT(31)
>> +#define AARCH64_INSN_S_BIT BIT(29)
>> #define AARCH64_INSN_N_BIT BIT(22)
>>
>> static int aarch64_insn_encoding_class[] = {
>> @@ -1141,3 +1142,104 @@ u32 aarch32_insn_mcr_extract_crm(u32 insn)
>> {
>> return insn & CRM_MASK;
>> }
>> +
>> +enum aarch64_insn_register aarch64_insn_extract_reg_num(u32 insn,
>> + enum aarch64_insn_register_type type)
>> +{
>> + int shift;
>> +
>> + switch (type) {
>> + case AARCH64_INSN_REGTYPE_RT:
>> + case AARCH64_INSN_REGTYPE_RD:
>> + shift = 0;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RN:
>> + shift = 5;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RT2:
>> + case AARCH64_INSN_REGTYPE_RA:
>> + shift = 10;
>> + break;
>> + case AARCH64_INSN_REGTYPE_RM:
>> + shift = 16;
>> + break;
>> + default:
>> + pr_err("%s: unknown register type decoding %d\n", __func__,
>> + type);
>> + return ~0L;
>> + }
>> +
>> + return (insn & (GENMASK(4, 0) << shift)) >> shift;
>> +}
>> +
>> +int aarch64_insn_decode_add_sub_imm(u32 insn,
>> + enum aarch64_insn_register *dst,
>> + enum aarch64_insn_register *src,
>> + int *imm,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_adsb_type *type)
>> +{
>> + if (aarch64_insn_is_add_imm(insn))
>> + *type = ((insn) & AARCH64_INSN_S_BIT) ?
>> + AARCH64_INSN_ADSB_ADD_SETFLAGS :
>> + AARCH64_INSN_ADSB_ADD;
>> + else if (aarch64_insn_is_sub_imm(insn))
>> + *type = ((insn) & AARCH64_INSN_S_BIT) ?
>> + AARCH64_INSN_ADSB_SUB_SETFLAGS :
>> + AARCH64_INSN_ADSB_SUB;
>> + else
>> + return 0;
>> +
>> + *variant = (insn & AARCH64_INSN_SF_BIT) ? AARCH64_INSN_VARIANT_64BIT :
>> + AARCH64_INSN_VARIANT_32BIT;
>> +
>> + *dst = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RD);
>> +
>> + *src = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RN);
>> +
>> + /* TODO: ignore shilft field[23:22] */
>> + *imm = (int)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_12, insn);
>> +
>> + return 1;
>> +}
>> +
>> +int aarch64_insn_decode_load_store_pair(u32 insn,
>> + enum aarch64_insn_register *reg1,
>> + enum aarch64_insn_register *reg2,
>> + enum aarch64_insn_register *base,
>> + int *offset,
>> + enum aarch64_insn_variant *variant,
>> + enum aarch64_insn_ldst_type *type)
>> +{
>> + int imm;
>> +
>> + if (aarch64_insn_is_stp(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR;
>> + else if (aarch64_insn_is_stp_post(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR_POST_INDEX;
>> + else if (aarch64_insn_is_stp_pre(insn))
>> + *type = AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX;
>> + else if (aarch64_insn_is_ldp(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR;
>> + else if (aarch64_insn_is_ldp_post(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR_POST_INDEX;
>> + else if (aarch64_insn_is_ldp_pre(insn))
>> + *type = AARCH64_INSN_LDST_LOAD_PAIR_PRE_INDEX;
>> + else
>> + return 0;
>> +
>> + *variant = (insn & AARCH64_INSN_S_BIT) ? AARCH64_INSN_VARIANT_64BIT :
>> + AARCH64_INSN_VARIANT_32BIT;
>> +
>> + *reg1 = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RT);
>> +
>> + *reg2 = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RT2);
>> +
>> + *base = aarch64_insn_extract_reg_num(insn, AARCH64_INSN_REGTYPE_RN);
>> +
>> + imm = (int)aarch64_insn_decode_immediate(AARCH64_INSN_IMM_7, insn);
>> + asm("sbfm %0, %0, 0, 6" : "+r" (imm));
>> + *offset = imm * 8;
>> +
>> + return 1;
>> +}
>> --
>> 1.7.9.5
>>
>
next prev parent reply other threads:[~2015-11-11 4:54 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-06 6:44 [PATCH v5 0/6] arm64: ftrace: fix incorrect output from stack tracer AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-06 6:44 ` [PATCH v5 1/6] arm64: ftrace: modify a stack frame in a safe way AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-06 6:44 ` [PATCH v5 2/6] arm64: ftrace: fix a stack tracer's output under function graph tracer AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-09 14:04 ` Jungseok Lee
2015-11-09 14:04 ` Jungseok Lee
2015-11-10 2:42 ` AKASHI Takahiro
2015-11-10 2:42 ` AKASHI Takahiro
2015-11-13 15:01 ` Jungseok Lee
2015-11-13 15:01 ` Jungseok Lee
2015-11-16 9:23 ` AKASHI Takahiro
2015-11-16 9:23 ` AKASHI Takahiro
2015-11-06 6:44 ` [PATCH v5 3/6] ftrace: allow arch-specific stack tracer AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-06 13:39 ` Steven Rostedt
2015-11-06 13:39 ` Steven Rostedt
2015-11-06 6:44 ` [PATCH v5 4/6] arm64: insn: add instruction decoders for ldp/stp and add/sub AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-10 13:40 ` Jungseok Lee
2015-11-10 13:40 ` Jungseok Lee
2015-11-11 4:54 ` AKASHI Takahiro [this message]
2015-11-11 4:54 ` AKASHI Takahiro
2015-11-06 6:44 ` [PATCH v5 5/6] arm64: ftrace: add arch-specific stack tracer AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-10 14:05 ` Jungseok Lee
2015-11-10 14:05 ` Jungseok Lee
2015-11-11 5:03 ` AKASHI Takahiro
2015-11-11 5:03 ` AKASHI Takahiro
2015-11-11 22:56 ` Jungseok Lee
2015-11-11 22:56 ` Jungseok Lee
2015-11-06 6:44 ` [PATCH v5 6/6] arm64: ftrace: add a test of function prologue analyzer AKASHI Takahiro
2015-11-06 6:44 ` AKASHI Takahiro
2015-11-09 14:24 ` [PATCH v5 0/6] arm64: ftrace: fix incorrect output from stack tracer Jungseok Lee
2015-11-09 14:24 ` Jungseok Lee
2015-11-10 2:58 ` AKASHI Takahiro
2015-11-10 2:58 ` AKASHI Takahiro
2015-11-10 13:32 ` Jungseok Lee
2015-11-10 13:32 ` Jungseok Lee
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=5642CA0D.9080708@linaro.org \
--to=takahiro.akashi@linaro.org \
--cc=linux-arm-kernel@lists.infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.