From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1944) id 873C7385153A; Thu, 27 Oct 2022 13:59:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 873C7385153A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666879194; bh=jnyrHR2LFZ+QRbSqW/cXVevRQkkmVoRMH0e8qjwn6Ks=; h=From:To:Subject:Date:From; b=VyFkvgolcr9unJ5HPxWbYmDimsoIN0eKJt0G6aebgB8wwazBsZTxn9pjucqPVaSZv rsPWRDKR3KRRMwzFxtWh0D3MR9il+R7Zvhiy6siMcMOlsWAspkBIA03hmfcMNZDZ+9 /zP5NezjAWiBbtAlXGr4yuBPEQhBh8i8HyiRbWPk= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Szabolcs Nagy To: glibc-cvs@sourceware.org Subject: [glibc/arm/morello/main] cheri: stdio-common: add support for printing CHERI capabilities X-Act-Checkin: glibc X-Git-Author: Carlos Eduardo Seo X-Git-Refname: refs/heads/arm/morello/main X-Git-Oldrev: c6827cd8b558a4fa191ad285bde4a17efdd758db X-Git-Newrev: cfa623ce10c5d1319f3a8345930a5044b3471e57 Message-Id: <20221027135954.873C7385153A@sourceware.org> Date: Thu, 27 Oct 2022 13:59:54 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=cfa623ce10c5d1319f3a8345930a5044b3471e57 commit cfa623ce10c5d1319f3a8345930a5044b3471e57 Author: Carlos Eduardo Seo Date: Thu Jul 7 18:46:43 2022 +0000 cheri: stdio-common: add support for printing CHERI capabilities This adds a new modifier %#p for printing capability information according to the CHERI C Programming guide: https://github.com/CTSRD-CHERI/cheri-c-programming/wiki/Displaying-Capabilities A %#p option in printf will display:
[,-] () * address: Virtual address of capability displayed as a hexadecimal value with a 0x prefix. * permissions: Zero or more of the following characters: r: LOAD permission w: STORE permission x: EXECUTE permission R: LOAD_CAP permission W: STORE_CAP permission E: EXECUTIVE permission (Morello only) * base: Lower bound of capability displayed as a hexadecimal value with a 0x prefix. * top: Upper bound of capability plus 1 displayed as a hexadecimal value with a 0x prefix. * attr: Zero or more of the following comma-separated attributes. If none of the attributes are present, this field is omitted (along with the enclosing parentheses/brackets). invalid: Capability's tag is clear. sentry: Capability is a sealed entry. sealed: Capability is sealed with a type other than the sealed entry object type. A %p option in printf will display the capability value (address) normally. Diff: --- stdio-common/printf-parsemb.c | 5 ++ stdio-common/printf.h | 3 +- stdio-common/vfprintf-internal.c | 15 +++++ stdio-common/vfprintf-process-arg.c | 121 ++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c index 386e2a27bb..e9e395c2de 100644 --- a/stdio-common/printf-parsemb.c +++ b/stdio-common/printf-parsemb.c @@ -80,6 +80,7 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, spec->info.pad = ' '; spec->info.wide = sizeof (UCHAR_T) > 1; spec->info.is_binary128 = 0; + spec->info.is_cap = 0; /* Test for positional argument. */ if (ISDIGIT (*format)) @@ -371,6 +372,10 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn, break; case L'p': spec->data_arg_type = PA_POINTER; +#ifdef __CHERI_PURE_CAPABILITY__ + if (spec->info.alt) + spec->info.is_cap = 1; +#endif break; case L'n': spec->data_arg_type = PA_INT|PA_FLAG_PTR; diff --git a/stdio-common/printf.h b/stdio-common/printf.h index 46993e031e..815dc95779 100644 --- a/stdio-common/printf.h +++ b/stdio-common/printf.h @@ -50,7 +50,8 @@ struct printf_info unsigned int i18n:1; /* I flag. */ unsigned int is_binary128:1; /* Floating-point argument is ABI-compatible with IEC 60559 binary128. */ - unsigned int __pad:3; /* Unused so far. */ + unsigned int is_cap:1; /* CHERI capability. */ + unsigned int __pad:2; /* Unused so far. */ unsigned short int user; /* Bits for user-installed modifiers. */ wchar_t pad; /* Padding character. */ }; diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c index fb94961f37..c2f1904b7d 100644 --- a/stdio-common/vfprintf-internal.c +++ b/stdio-common/vfprintf-internal.c @@ -116,6 +116,10 @@ while (0) #endif +#ifdef __CHERI_PURE_CAPABILITY__ +# include +#endif + /* Add LENGTH to DONE. Return the new value of DONE, or -1 on overflow (and set errno accordingly). */ static inline int @@ -792,6 +796,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) int base; union printf_arg the_arg; CHAR_T *string; /* Pointer to argument string. */ +#ifdef __CHERI_PURE_CAPABILITY__ + const void *cap = 0; +#endif int alt = 0; /* Alternate format. */ int space = 0; /* Use space prefix if no sign is needed. */ int left = 0; /* Left-justify output. */ @@ -805,6 +812,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags) int is_char = 0; /* Argument is promoted (unsigned) char. */ int width = 0; /* Width of output; 0 means none specified. */ int prec = -1; /* Precision of output; -1 means none specified. */ + __attribute__((unused)) + int is_cap = 0; /* Argument is a capability. */ + /* This flag is set by the 'I' modifier and selects the use of the `outdigits' as determined by the current locale. */ int use_outdigits = 0; @@ -1324,6 +1334,9 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, } number; int base; CHAR_T *string; /* Pointer to argument string. */ +#ifdef __CHERI_PURE_CAPABILITY__ + const void *cap = 0; +#endif /* Fill variables from values in struct. */ int alt = specs[nspecs_done].info.alt; @@ -1338,6 +1351,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format, int is_long = specs[nspecs_done].info.is_long; int width = specs[nspecs_done].info.width; int prec = specs[nspecs_done].info.prec; + __attribute__((unused)) + int is_cap = specs[nspecs_done].info.is_cap; int use_outdigits = specs[nspecs_done].info.i18n; char pad = specs[nspecs_done].info.pad; CHAR_T spec = specs[nspecs_done].info.spec; diff --git a/stdio-common/vfprintf-process-arg.c b/stdio-common/vfprintf-process-arg.c index 4fe369e111..709d2c7db7 100644 --- a/stdio-common/vfprintf-process-arg.c +++ b/stdio-common/vfprintf-process-arg.c @@ -25,6 +25,115 @@ { /* Start real work. We know about all flags and modifiers and now process the wanted format specifier. */ + +/* Process capability information according to the CHERI C Programming guide: + https://github.com/CTSRD-CHERI/cheri-c-programming/wiki/Displaying-Capabilities */ +#ifdef __CHERI_PURE_CAPABILITY__ +LABEL (capability): + /* CHERI capability. */ + { + uint64_t cap_perm = 0; + uint64_t cap_base = 0; + uint64_t cap_limit = 0; + uint64_t cap_tag = 0; + uint64_t cap_type = 0; + outchar (L_(' ')); + outchar (L_('[')); + cap_perm = __builtin_cheri_perms_get (cap); + if (cap_perm & CAP_PERM_LOAD) + outchar (L_('r')); + if (cap_perm & CAP_PERM_STORE) + outchar (L_('w')); + if (cap_perm & CAP_PERM_EXECUTE) + outchar (L_('x')); + if (cap_perm & CAP_PERM_LOAD_CAP) + outchar (L_('R')); + if (cap_perm & CAP_PERM_STORE_CAP) + outchar (L_('W')); + if (cap_perm & CAP_PERM_EXECUTIVE) + outchar (L_('E')); + outchar (L_(',')); + cap_base = __builtin_cheri_base_get (cap); + number.word = (unsigned long int) cap_base; + if (prec < 0) + prec = 1; + else + pad = L_(' '); + string = _itoa_word (number.word, workend, base, spec == L_('X')); + prec = MAX (0, prec - (workend - string)); + width -= workend - string + prec; + if (number.word != 0) + width -= 2; + if (pad == L_(' ')) + { + PAD (L_(' ')); + width = 0; + } + if (number.word != 0) + { + outchar (L_('0')); + outchar (spec); + } + width += prec; + PAD (L_('0')); + outstring (string, workend - string); + outchar (L_('-')); + cap_limit = __builtin_cheri_length_get (cap) + cap_base; + number.word = (unsigned long int) cap_limit; + if (prec < 0) + prec = 1; + else + pad = L_(' '); + string = _itoa_word (number.word, workend, base, spec == L_('X')); + prec = MAX (0, prec - (workend - string)); + width -= workend - string + prec; + if (number.word != 0) + width -= 2; + if (pad == L_(' ')) + { + PAD (L_(' ')); + width = 0; + } + if (number.word != 0) + { + outchar (L_('0')); + outchar (spec); + } + width += prec; + PAD (L_('0')); + outstring (string, workend - string); + outchar (L_(']')); + cap_tag = __builtin_cheri_tag_get (cap); + if (!cap_tag) + { + outchar (L_(' ')); + outchar (L_('(')); + outstring ("invalid", 8); + outchar (L_(')')); + break; + } + cap_type = __builtin_cheri_type_get (cap); + if (cap_type != 0) + { + if (cap_type == 1) + { + outchar (L_(' ')); + outchar (L_('(')); + outstring ("sentry", 7); + outchar (L_(')')); + } + else + { + outchar (L_(' ')); + outchar (L_('(')); + outstring ("sealed", 7); + outchar (L_(')')); + } + } + } + break; +#endif + LABEL (form_percent): /* Write a literal "%". */ outchar (L_('%')); @@ -212,6 +321,11 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */ outstring (string, workend - string); +#ifdef __CHERI_PURE_CAPABILITY__ + if (is_cap == 1) + goto LABEL(capability); +#endif + break; } else @@ -265,6 +379,13 @@ LABEL (form_pointer): base = 16; number.word = (unsigned long int) ptr; is_negative = 0; +#ifdef __CHERI_PURE_CAPABILITY__ + if (alt == 1) + { + cap = ptr; + is_cap = 1; + } +#endif alt = 1; group = 0; spec = L_('x');