diff mbox series

[v2,1/4] xen: introduce CONFIG_GENERIC_BUG_FRAME

Message ID aa0d3704921f5ec04b66c8aa935638a64018c50b.1676909088.git.oleksii.kurochko@gmail.com (mailing list archive)
State Superseded
Headers show
Series introduce generic implementation of macros from bug.h | expand

Commit Message

Oleksii Kurochko Feb. 20, 2023, 4:40 p.m. UTC
A large part of the content of the bug.h is repeated among all
architectures, so it was decided to create a new config
CONFIG_GENERIC_BUG_FRAME.

The version of <bug.h> from x86 was taken as the base version.

The patch introduces the following stuff:
  * common bug.h header
  * generic implementation of do_bug_frame()
  * new config CONFIG_GENERIC_BUG_FRAME

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>

---
Changes in V2:
  - Switch to x86 implementation as generic as it is more compact
    ( at least from the point of view of bug frame structure ).
  - Rename CONFIG_GENERIC_DO_BUG_FRAME to CONFIG_GENERIC_BUG_FRAME.
  - Change the macro bug_loc(b) to avoid the need for a cast:
    #define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
  - Rename BUG_FRAME_STUFF to BUG_FRAME_STRUCT
  - Make macros related to bug frame structure more generic.
  - Introduce BUG_INSTR and MODIFIER to make _ASM_BUGFRAME_TEXT reusable
    between x86 and RISC-V.
  - Rework do_bug_frame() and introduce find_bug_frame() and handle_bug_frame()
    functions to make it reusable by x86.
  - code style fixes
---
 xen/common/Kconfig    |   3 +
 xen/common/Makefile   |   1 +
 xen/common/bug.c      | 113 +++++++++++++++++++++++++++++
 xen/include/xen/bug.h | 161 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 278 insertions(+)
 create mode 100644 xen/common/bug.c
 create mode 100644 xen/include/xen/bug.h

Comments

Jan Beulich Feb. 22, 2023, 12:46 p.m. UTC | #1
On 20.02.2023 17:40, Oleksii Kurochko wrote:
> A large part of the content of the bug.h is repeated among all
> architectures, so it was decided to create a new config
> CONFIG_GENERIC_BUG_FRAME.
> 
> The version of <bug.h> from x86 was taken as the base version.
> 
> The patch introduces the following stuff:
>   * common bug.h header
>   * generic implementation of do_bug_frame()
>   * new config CONFIG_GENERIC_BUG_FRAME
> 
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> 
> ---
> Changes in V2:
>   - Switch to x86 implementation as generic as it is more compact
>     ( at least from the point of view of bug frame structure ).
>   - Rename CONFIG_GENERIC_DO_BUG_FRAME to CONFIG_GENERIC_BUG_FRAME.
>   - Change the macro bug_loc(b) to avoid the need for a cast:
>     #define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
>   - Rename BUG_FRAME_STUFF to BUG_FRAME_STRUCT
>   - Make macros related to bug frame structure more generic.
>   - Introduce BUG_INSTR and MODIFIER to make _ASM_BUGFRAME_TEXT reusable
>     between x86 and RISC-V.

Hmm, below I see it's really just "MODIFIER". I see two issues with this:
For one the name is too generic for something which cannot be #undef-ed
after use inside the header. And then it also doesn't really say what is
being modified. While ending up longer, how about BUG_ASM_CONST or alike?

I also think this should default to something if not overridden by an
arch. Perhaps simply to an expansion to nothing (at which point you
won't need to define it for RISC-V, aiui).

> --- /dev/null
> +++ b/xen/common/bug.c
> @@ -0,0 +1,113 @@
> +#include <xen/bug.h>
> +#include <xen/errno.h>
> +#include <xen/kernel.h>
> +#include <xen/livepatch.h>
> +#include <xen/string.h>
> +#include <xen/types.h>
> +#include <xen/virtual_region.h>
> +
> +#include <asm/processor.h>

Is this really needed here?

> +const struct bug_frame* find_bug_frame(unsigned long pc, unsigned int *id)

Is this function going to be needed outside of this CU? IOW why is it not
static?

Also, nit: Left most star wants changing places with the adjacent blank.

> +{
> +    const struct bug_frame *bug = NULL;
> +    const struct virtual_region *region;
> +
> +    region = find_text_region(pc);
> +    if ( region )
> +    {
> +        for ( *id = 0; *id < BUGFRAME_NR; (*id)++ )
> +        {
> +            const struct bug_frame *b;
> +            unsigned int i;
> +
> +            for ( i = 0, b = region->frame[*id].bugs;
> +                  i < region->frame[*id].n_bugs; b++, i++ )
> +            {
> +                if ( bug_loc(b) == pc )
> +                {
> +                    bug = b;
> +                    goto found;

While in the original code the goto is kind of warranted, it isn't really
here imo. You can simply "return b" here and ...

> +                }
> +            }
> +        }
> +    }
> +
> + found:
> +    return bug;

... "return NULL" here. That'll allow the function scope "bug" to go away,
at which point the inner scope "b" can become "bug".

> +}
> +
> +int handle_bug_frame(const struct cpu_user_regs *regs,
> +                    const struct bug_frame *bug,
> +                    unsigned int id)

Nit: Indentation is off by one here. Also same question regarding the lack
of static here.

> +{
> +    const char *prefix = "", *filename, *predicate;
> +    unsigned long fixup;
> +    unsigned int lineno;
> +
> +    if ( id == BUGFRAME_run_fn )
> +    {
> +#ifdef ARM        

Who or what defines ARM? Anyway, seeing ...

> +        void (*fn)(const struct cpu_user_regs *) = (void *)regs->BUG_FN_REG;

... this, wouldn't it be better (and independent of the specific arch) if
you checked for BUG_FN_REG being defined?

Another (#ifdef-free) variant would be to have bug_ptr() take a 2nd argument
and then uniformly use ...

> +#else
> +        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug);

... this, slightly altered to

        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug, regs);

> +#endif
> +
> +        fn(regs);
> +        return 0;
> +    }
> +
> +    /* WARN, BUG or ASSERT: decode the filename pointer and line number. */
> +    filename = bug_ptr(bug);
> +    if ( !is_kernel(filename) && !is_patch(filename) )
> +        return -EINVAL;
> +    fixup = strlen(filename);
> +    if ( fixup > 50 )
> +    {
> +        filename += fixup - 47;
> +        prefix = "...";
> +    }
> +    lineno = bug_line(bug);
> +
> +    switch ( id )
> +    {
> +    case BUGFRAME_warn:
> +        printk("Xen WARN at %s%s:%d\n", prefix, filename, lineno);
> +        show_execution_state(regs);
> +        return 0;
> +
> +    case BUGFRAME_bug:
> +        printk("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
> +
> +        show_execution_state(regs);
> +        panic("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
> +
> +    case BUGFRAME_assert:
> +        /* ASSERT: decode the predicate string pointer. */
> +        predicate = bug_msg(bug);
> +        if ( !is_kernel(predicate) )
> +            predicate = "<unknown>";
> +
> +        printk("Assertion '%s' failed at %s%s:%d\n",
> +               predicate, prefix, filename, lineno);
> +
> +        show_execution_state(regs);
> +        panic("Assertion '%s' failed at %s%s:%d\n",
> +              predicate, prefix, filename, lineno);
> +    }
> +
> +    return -EINVAL;
> +}
> +
> +int do_bug_frame(const struct cpu_user_regs *regs, unsigned long pc)
> +{
> +    const struct bug_frame *bug = NULL;

Nit: pointless initializer. You could of course have the assignment below
become the initializer here.

> +    unsigned int id;
> +
> +    bug = find_bug_frame(pc, &id);
> +    if (!bug)

Nit: Style (missing blanks).

> --- /dev/null
> +++ b/xen/include/xen/bug.h
> @@ -0,0 +1,161 @@
> +#ifndef __XEN_BUG_H__
> +#define __XEN_BUG_H__
> +
> +#define BUG_DISP_WIDTH    24
> +#define BUG_LINE_LO_WIDTH (31 - BUG_DISP_WIDTH)
> +#define BUG_LINE_HI_WIDTH (31 - BUG_DISP_WIDTH)
> +
> +#define BUGFRAME_run_fn 0
> +#define BUGFRAME_warn   1
> +#define BUGFRAME_bug    2
> +#define BUGFRAME_assert 3
> +
> +#define BUGFRAME_NR     4
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <xen/errno.h>
> +#include <xen/lib.h>
> +#include <xen/stringify.h>
> +#include <xen/types.h>
> +
> +#include <asm/bug.h>

Any reason this cannot live ahead of the #ifndef, eliminating the need for
an #else further down?

> +#ifndef BUG_FRAME_STRUCT
> +
> +struct bug_frame {
> +    signed int loc_disp:BUG_DISP_WIDTH;
> +    unsigned int line_hi:BUG_LINE_HI_WIDTH;
> +    signed int ptr_disp:BUG_DISP_WIDTH;
> +    unsigned int line_lo:BUG_LINE_LO_WIDTH;
> +    signed int msg_disp[];
> +};
> +
> +#endif /* BUG_FRAME_STRUCT */
> +
> +#ifndef bug_loc
> +#define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
> +#endif /* bug_loc */

For short #if / #ifdef I don't think such comments are necessary on the
#else or #endif; personally I consider such to hamper readability.

> +#ifndef bug_ptr
> +#define bug_ptr(b) ((const void *)(b) + (b)->ptr_disp)
> +#endif /* bug_ptr */
> +
> +#ifndef bug_line
> +#define bug_line(b) (((((b)->line_hi + ((b)->loc_disp < 0)) &                \
> +                       ((1 << BUG_LINE_HI_WIDTH) - 1)) <<                    \
> +                      BUG_LINE_LO_WIDTH) +                                   \
> +                     (((b)->line_lo + ((b)->ptr_disp < 0)) &                 \
> +                      ((1 << BUG_LINE_LO_WIDTH) - 1)))
> +#endif /* bug_line */
> +
> +#ifndef bug_msg
> +#define bug_msg(b) ((const char *)(b) + (b)->msg_disp[1])
> +#endif /* bug_msg */
> +
> +#ifndef _ASM_BUGFRAME_TEXT
> +
> +#define _ASM_BUGFRAME_TEXT(second_frame)                                    \
> +    ".Lbug%=:"BUG_INSTR"\n"                                                 \
> +    ".pushsection .bug_frames.%"MODIFIER"[bf_type], \"a\", @progbits\n"      \

You may want to use %progbits here right away, as being the more portable
form.

> +    ".p2align 2\n"                                                          \
> +    ".Lfrm%=:\n"                                                            \
> +    ".long (.Lbug%= - .Lfrm%=) + %"MODIFIER"[bf_line_hi]\n"                  \
> +    ".long (%"MODIFIER"[bf_ptr] - .Lfrm%=) + %"MODIFIER"[bf_line_lo]\n"       \
> +    ".if " #second_frame "\n"                                               \
> +    ".long 0, %"MODIFIER"[bf_msg] - .Lfrm%=\n"                               \
> +    ".endif\n"                                                              \
> +    ".popsection\n"

I think I said so in reply to an earlier version already: The moment
assembly code moves to a common header, it should be adjusted to be as
portable as possible. In particular directives should never start at the
beginning of a line, while labels always should. (Whether .long is
actually portable is another question, which I'll be happy to leave
aside for now.)

Also nit (style): The line continuation characters want to all line up.

> +#endif /* _ASM_BUGFRAME_TEXT */
> +
> +#ifndef _ASM_BUGFRAME_INFO

I don't think these two make sense for an arch to define independently.
INFO absolutely has to match TEXT, so I think an arch should always
define (or not) both together.

> +#define _ASM_BUGFRAME_INFO(type, line, ptr, msg)                             \
> +    [bf_type]    "i" (type),                                                 \
> +    [bf_ptr]     "i" (ptr),                                                  \
> +    [bf_msg]     "i" (msg),                                                  \
> +    [bf_line_lo] "i" ((line & ((1 << BUG_LINE_LO_WIDTH) - 1))                \
> +                      << BUG_DISP_WIDTH),                                    \
> +    [bf_line_hi] "i" (((line) >> BUG_LINE_LO_WIDTH) << BUG_DISP_WIDTH)
> +
> +#endif /* _ASM_BUGFRAME_INFO */
> +
> +#ifndef BUG_FRAME
> +
> +#define BUG_FRAME(type, line, ptr, second_frame, msg) do {                   \
> +    BUILD_BUG_ON((line) >> (BUG_LINE_LO_WIDTH + BUG_LINE_HI_WIDTH));         \
> +    BUILD_BUG_ON((type) >= BUGFRAME_NR);                                     \
> +    asm volatile ( _ASM_BUGFRAME_TEXT(second_frame)                          \
> +                   :: _ASM_BUGFRAME_INFO(type, line, ptr, msg) );            \
> +} while (0)
> +
> +#endif
> +
> +#ifndef run_in_exception_handler
> +
> +/*
> + * TODO: untangle header dependences, break BUILD_BUG_ON() out of xen/lib.h,
> + * and use a real static inline here to get proper type checking of fn().
> + */

I realize you only copy this comment, but I'm having a hard time seeing
the connection to BUILD_BUG_ON() here. Would be nice if the comment was
"generalized" in a form that actually can be understood. Andrew?

> +#define run_in_exception_handler(fn)                            \
> +    do {                                                        \
> +        (void)((fn) == (void (*)(struct cpu_user_regs *))NULL); \
> +        BUG_FRAME(BUGFRAME_run_fn, 0, fn, 0, NULL);             \
> +    } while ( 0 )
> +
> +#endif /* run_in_exception_handler */
> +
> +#ifndef WARN
> +#define WARN() BUG_FRAME(BUGFRAME_warn, __LINE__, __FILE__, 0, NULL)
> +#endif /* WARN */

No real need for the comment here; you also have none below for e.g.
BUG().

Jan
Oleksii Kurochko Feb. 22, 2023, 4:16 p.m. UTC | #2
Hello Jan,

On Wed, 2023-02-22 at 13:46 +0100, Jan Beulich wrote:
> On 20.02.2023 17:40, Oleksii Kurochko wrote:
> > A large part of the content of the bug.h is repeated among all
> > architectures, so it was decided to create a new config
> > CONFIG_GENERIC_BUG_FRAME.
> > 
> > The version of <bug.h> from x86 was taken as the base version.
> > 
> > The patch introduces the following stuff:
> >   * common bug.h header
> >   * generic implementation of do_bug_frame()
> >   * new config CONFIG_GENERIC_BUG_FRAME
> > 
> > Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
> > 
> > ---
> > Changes in V2:
> >   - Switch to x86 implementation as generic as it is more compact
> >     ( at least from the point of view of bug frame structure ).
> >   - Rename CONFIG_GENERIC_DO_BUG_FRAME to CONFIG_GENERIC_BUG_FRAME.
> >   - Change the macro bug_loc(b) to avoid the need for a cast:
> >     #define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
> >   - Rename BUG_FRAME_STUFF to BUG_FRAME_STRUCT
> >   - Make macros related to bug frame structure more generic.
> >   - Introduce BUG_INSTR and MODIFIER to make _ASM_BUGFRAME_TEXT
> > reusable
> >     between x86 and RISC-V.
> 
> Hmm, below I see it's really just "MODIFIER". I see two issues with
> this:
> For one the name is too generic for something which cannot be #undef-
> ed
> after use inside the header. And then it also doesn't really say what
> is
> being modified. While ending up longer, how about BUG_ASM_CONST or
> alike?
BUG_ASM_CONST will be much better.
> 
> I also think this should default to something if not overridden by an
> arch. Perhaps simply to an expansion to nothing (at which point you
> won't need to define it for RISC-V, aiui).
> 
Agree.

Initially, I thought about that too but couldn't estimate how well the
modifier '%c' is supported, deciding that each architecture has to
define it.

But we can make it equal to nothing (at least for 2 architectures ) it
doesn't have the same support as in x86.

> > --- /dev/null
> > +++ b/xen/common/bug.c
> > @@ -0,0 +1,113 @@
> > +#include <xen/bug.h>
> > +#include <xen/errno.h>
> > +#include <xen/kernel.h>
> > +#include <xen/livepatch.h>
> > +#include <xen/string.h>
> > +#include <xen/types.h>
> > +#include <xen/virtual_region.h>
> > +
> > +#include <asm/processor.h>
> 
> Is this really needed here?
Yes, it is.

Function show_execution_state() is declared in this header for all
architectures and is used by handle_bug_frame().
> 
> > +const struct bug_frame* find_bug_frame(unsigned long pc, unsigned
> > int *id)
> 
> Is this function going to be needed outside of this CU? IOW why is it
> not
> static?
> 
It's not static because there is not possible to use do_bug_frame() as
is for x86 as x86 has some additional checks for some cases which
aren't in generic implementation:
[1]
https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1217
[2]
https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1238
[3]
https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1259

Probably to make generic do_bug_frame() more re-usable for x86 we can
implement as stubs fixup_exception_return() and debugger_trap_fatal()
under #ifndef X86 ... #endif inside common/bug.c.

Could you please share your thoughts about that?

> Also, nit: Left most star wants changing places with the adjacent
> blank.
Thanks. I'll update in the next version of the patch series.

> 
> > +{
> > +    const struct bug_frame *bug = NULL;
> > +    const struct virtual_region *region;
> > +
> > +    region = find_text_region(pc);
> > +    if ( region )
> > +    {
> > +        for ( *id = 0; *id < BUGFRAME_NR; (*id)++ )
> > +        {
> > +            const struct bug_frame *b;
> > +            unsigned int i;
> > +
> > +            for ( i = 0, b = region->frame[*id].bugs;
> > +                  i < region->frame[*id].n_bugs; b++, i++ )
> > +            {
> > +                if ( bug_loc(b) == pc )
> > +                {
> > +                    bug = b;
> > +                    goto found;
> 
> While in the original code the goto is kind of warranted, it isn't
> really
> here imo. You can simply "return b" here and ...
> 
> > +                }
> > +            }
> > +        }
> > +    }
> > +
> > + found:
> > +    return bug;
> 
> ... "return NULL" here. That'll allow the function scope "bug" to go
> away,
> at which point the inner scope "b" can become "bug".
Agree, missed that when decided to move that part of the code to
separate function.

> 
> > +}
> > +
> > +int handle_bug_frame(const struct cpu_user_regs *regs,
> > +                    const struct bug_frame *bug,
> > +                    unsigned int id)
> 
> Nit: Indentation is off by one here. Also same question regarding the
> lack
> of static here.
Regarding static an answer is the same as with previous one static
question.

> 
> > +{
> > +    const char *prefix = "", *filename, *predicate;
> > +    unsigned long fixup;
> > +    unsigned int lineno;
> > +
> > +    if ( id == BUGFRAME_run_fn )
> > +    {
> > +#ifdef ARM        
> 
> Who or what defines ARM? Anyway, seeing ...
it is defined by default in Kconfig:
https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/arm/Kconfig#L13
> 
> > +        void (*fn)(const struct cpu_user_regs *) = (void *)regs-
> > >BUG_FN_REG;
> 
> ... this, wouldn't it be better (and independent of the specific
> arch) if
> you checked for BUG_FN_REG being defined?
If I understand Kconfig correctly than there is no significant
difference what check. But probably BUG_FN_REG would be a little bit
better if someone will decide to change a way how pointer to function
will be passed in case of ARM than we will get compilation error and so
won't miss to fix the line in do_bug_frame().

> 
> Another (#ifdef-free) variant would be to have bug_ptr() take a 2nd
> argument
> and then uniformly use ...
> 
> > +#else
> > +        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug);
> 
> ... this, slightly altered to
> 
>         void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug,
> regs);
Probably this one option will be the most universal and we have to
stick to it.
> 
> > +#endif
> > +
> > +        fn(regs);
> > +        return 0;
> > +    }
> > +
> > +    /* WARN, BUG or ASSERT: decode the filename pointer and line
> > number. */
> > +    filename = bug_ptr(bug);
> > +    if ( !is_kernel(filename) && !is_patch(filename) )
> > +        return -EINVAL;
> > +    fixup = strlen(filename);
> > +    if ( fixup > 50 )
> > +    {
> > +        filename += fixup - 47;
> > +        prefix = "...";
> > +    }
> > +    lineno = bug_line(bug);
> > +
> > +    switch ( id )
> > +    {
> > +    case BUGFRAME_warn:
> > +        printk("Xen WARN at %s%s:%d\n", prefix, filename, lineno);
> > +        show_execution_state(regs);
> > +        return 0;
> > +
> > +    case BUGFRAME_bug:
> > +        printk("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
> > +
> > +        show_execution_state(regs);
> > +        panic("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
> > +
> > +    case BUGFRAME_assert:
> > +        /* ASSERT: decode the predicate string pointer. */
> > +        predicate = bug_msg(bug);
> > +        if ( !is_kernel(predicate) )
> > +            predicate = "<unknown>";
> > +
> > +        printk("Assertion '%s' failed at %s%s:%d\n",
> > +               predicate, prefix, filename, lineno);
> > +
> > +        show_execution_state(regs);
> > +        panic("Assertion '%s' failed at %s%s:%d\n",
> > +              predicate, prefix, filename, lineno);
> > +    }
> > +
> > +    return -EINVAL;
> > +}
> > +
> > +int do_bug_frame(const struct cpu_user_regs *regs, unsigned long
> > pc)
> > +{
> > +    const struct bug_frame *bug = NULL;
> 
> Nit: pointless initializer. You could of course have the assignment
> below
> become the initializer here.
Thanks. I'll update it the next version of the patch.
> 
> > +    unsigned int id;
> > +
> > +    bug = find_bug_frame(pc, &id);
> > +    if (!bug)
> 
> Nit: Style (missing blanks).
Thanks. I'll update it the next version of the patch.
> 
> > --- /dev/null
> > +++ b/xen/include/xen/bug.h
> > @@ -0,0 +1,161 @@
> > +#ifndef __XEN_BUG_H__
> > +#define __XEN_BUG_H__
> > +
> > +#define BUG_DISP_WIDTH    24
> > +#define BUG_LINE_LO_WIDTH (31 - BUG_DISP_WIDTH)
> > +#define BUG_LINE_HI_WIDTH (31 - BUG_DISP_WIDTH)
> > +
> > +#define BUGFRAME_run_fn 0
> > +#define BUGFRAME_warn   1
> > +#define BUGFRAME_bug    2
> > +#define BUGFRAME_assert 3
> > +
> > +#define BUGFRAME_NR     4
> > +
> > +#ifndef __ASSEMBLY__
> > +
> > +#include <xen/errno.h>
> > +#include <xen/lib.h>
> > +#include <xen/stringify.h>
> > +#include <xen/types.h>
> > +
> > +#include <asm/bug.h>
> 
> Any reason this cannot live ahead of the #ifndef, eliminating the
> need for
> an #else further down?
It should be fine.
Probably I had some issues during the initial stage of making bug.h
more generic...

> 
> > +#ifndef BUG_FRAME_STRUCT
> > +
> > +struct bug_frame {
> > +    signed int loc_disp:BUG_DISP_WIDTH;
> > +    unsigned int line_hi:BUG_LINE_HI_WIDTH;
> > +    signed int ptr_disp:BUG_DISP_WIDTH;
> > +    unsigned int line_lo:BUG_LINE_LO_WIDTH;
> > +    signed int msg_disp[];
> > +};
> > +
> > +#endif /* BUG_FRAME_STRUCT */
> > +
> > +#ifndef bug_loc
> > +#define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
> > +#endif /* bug_loc */
> 
> For short #if / #ifdef I don't think such comments are necessary on
> the
> #else or #endif; personally I consider such to hamper readability.
Thanks. I'll take it into account.

> 
> > +#ifndef bug_ptr
> > +#define bug_ptr(b) ((const void *)(b) + (b)->ptr_disp)
> > +#endif /* bug_ptr */
> > +
> > +#ifndef bug_line
> > +#define bug_line(b) (((((b)->line_hi + ((b)->loc_disp < 0))
> > &                \
> > +                       ((1 << BUG_LINE_HI_WIDTH) - 1))
> > <<                    \
> > +                      BUG_LINE_LO_WIDTH)
> > +                                   \
> > +                     (((b)->line_lo + ((b)->ptr_disp < 0))
> > &                 \
> > +                      ((1 << BUG_LINE_LO_WIDTH) - 1)))
> > +#endif /* bug_line */
> > +
> > +#ifndef bug_msg
> > +#define bug_msg(b) ((const char *)(b) + (b)->msg_disp[1])
> > +#endif /* bug_msg */
> > +
> > +#ifndef _ASM_BUGFRAME_TEXT
> > +
> > +#define
> > _ASM_BUGFRAME_TEXT(second_frame)                                   
> > \
> > +   
> > ".Lbug%=:"BUG_INSTR"\n"                                            
> >      \
> > +    ".pushsection .bug_frames.%"MODIFIER"[bf_type], \"a\",
> > @progbits\n"      \
> 
> You may want to use %progbits here right away, as being the more
> portable
> form.
Sure. Thanks. I'll take that into account.
> 
> > +    ".p2align
> > 2\n"                                                          \
> > +   
> > ".Lfrm%=:\n"                                                       
> >      \
> > +    ".long (.Lbug%= - .Lfrm%=) +
> > %"MODIFIER"[bf_line_hi]\n"                  \
> > +    ".long (%"MODIFIER"[bf_ptr] - .Lfrm%=) +
> > %"MODIFIER"[bf_line_lo]\n"       \
> > +    ".if " #second_frame
> > "\n"                                               \
> > +    ".long 0, %"MODIFIER"[bf_msg] -
> > .Lfrm%=\n"                               \
> > +   
> > ".endif\n"                                                         
> >      \
> > +    ".popsection\n"
> 
> I think I said so in reply to an earlier version already: The moment
> assembly code moves to a common header, it should be adjusted to be
> as
> portable as possible. In particular directives should never start at
> the
> beginning of a line, while labels always should. (Whether .long is
> actually portable is another question, which I'll be happy to leave
> aside for now.)
I am not sure that I understand about which one directive we are
talking about... Are we talking about .{push/pop}section and .p2align?
Probably you can show me an example in Xen or other project?

> 
> Also nit (style): The line continuation characters want to all line
> up.
> 
> > +#endif /* _ASM_BUGFRAME_TEXT */
> > +
> > +#ifndef _ASM_BUGFRAME_INFO
> 
> I don't think these two make sense for an arch to define
> independently.
> INFO absolutely has to match TEXT, so I think an arch should always
> define (or not) both together.
You are right. I'll take into account that.
> 
> > +#define _ASM_BUGFRAME_INFO(type, line, ptr,
> > msg)                             \
> > +    [bf_type]    "i"
> > (type),                                                 \
> > +    [bf_ptr]     "i"
> > (ptr),                                                  \
> > +    [bf_msg]     "i"
> > (msg),                                                  \
> > +    [bf_line_lo] "i" ((line & ((1 << BUG_LINE_LO_WIDTH) -
> > 1))                \
> > +                      <<
> > BUG_DISP_WIDTH),                                    \
> > +    [bf_line_hi] "i" (((line) >> BUG_LINE_LO_WIDTH) <<
> > BUG_DISP_WIDTH)
> > +
> > +#endif /* _ASM_BUGFRAME_INFO */
> > +
> > +#ifndef BUG_FRAME
> > +
> > +#define BUG_FRAME(type, line, ptr, second_frame, msg) do
> > {                   \
> > +    BUILD_BUG_ON((line) >> (BUG_LINE_LO_WIDTH +
> > BUG_LINE_HI_WIDTH));         \
> > +    BUILD_BUG_ON((type) >=
> > BUGFRAME_NR);                                     \
> > +    asm volatile (
> > _ASM_BUGFRAME_TEXT(second_frame)                          \
> > +                   :: _ASM_BUGFRAME_INFO(type, line, ptr, msg)
> > );            \
> > +} while (0)
> > +
> > +#endif
> > +
> > +#ifndef run_in_exception_handler
> > +
> > +/*
> > + * TODO: untangle header dependences, break BUILD_BUG_ON() out of
> > xen/lib.h,
> > + * and use a real static inline here to get proper type checking
> > of fn().
> > + */
> 
> I realize you only copy this comment, but I'm having a hard time
> seeing
> the connection to BUILD_BUG_ON() here. Would be nice if the comment
> was
> "generalized" in a form that actually can be understood. Andrew?
> 
> > +#define run_in_exception_handler(fn)                            \
> > +    do {                                                        \
> > +        (void)((fn) == (void (*)(struct cpu_user_regs *))NULL); \
> > +        BUG_FRAME(BUGFRAME_run_fn, 0, fn, 0, NULL);             \
> > +    } while ( 0 )
> > +
> > +#endif /* run_in_exception_handler */
> > +
> > +#ifndef WARN
> > +#define WARN() BUG_FRAME(BUGFRAME_warn, __LINE__, __FILE__, 0,
> > NULL)
> > +#endif /* WARN */
> 
> No real need for the comment here; you also have none below for e.g.
> BUG().
Thanks.
> 
> Jan

~ Oleksii
Jan Beulich Feb. 23, 2023, 10:11 a.m. UTC | #3
On 22.02.2023 17:16, Oleksii wrote:
> On Wed, 2023-02-22 at 13:46 +0100, Jan Beulich wrote:
>> On 20.02.2023 17:40, Oleksii Kurochko wrote:
>>> --- /dev/null
>>> +++ b/xen/common/bug.c
>>> @@ -0,0 +1,113 @@
>>> +#include <xen/bug.h>
>>> +#include <xen/errno.h>
>>> +#include <xen/kernel.h>
>>> +#include <xen/livepatch.h>
>>> +#include <xen/string.h>
>>> +#include <xen/types.h>
>>> +#include <xen/virtual_region.h>
>>> +
>>> +#include <asm/processor.h>
>>
>> Is this really needed here?
> Yes, it is.
> 
> Function show_execution_state() is declared in this header for all
> architectures and is used by handle_bug_frame().

Ugly, but yes, you're right.

>>> +const struct bug_frame* find_bug_frame(unsigned long pc, unsigned
>>> int *id)
>>
>> Is this function going to be needed outside of this CU? IOW why is it
>> not
>> static?
>>
> It's not static because there is not possible to use do_bug_frame() as
> is for x86 as x86 has some additional checks for some cases which
> aren't in generic implementation:
> [1]
> https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1217
> [2]
> https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1238
> [3]
> https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1259
> 
> Probably to make generic do_bug_frame() more re-usable for x86 we can
> implement as stubs fixup_exception_return() and debugger_trap_fatal()
> under #ifndef X86 ... #endif inside common/bug.c.
> 
> Could you please share your thoughts about that?

Isn't all that's needed a suitable return value from the function,
for the caller to take appropriate further action? (Maybe even that
isn't really necessary.)

That said, debugger_trap_fatal() imo may sensibly be generalized,
and hence could be left in common code. Arm may simply stub this to
nothing then for the time being.

>>> +{
>>> +    const char *prefix = "", *filename, *predicate;
>>> +    unsigned long fixup;
>>> +    unsigned int lineno;
>>> +
>>> +    if ( id == BUGFRAME_run_fn )
>>> +    {
>>> +#ifdef ARM        
>>
>> Who or what defines ARM? Anyway, seeing ...
> it is defined by default in Kconfig:
> https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/arm/Kconfig#L13

That'll be CONFIG_ARM then in uses in C code.

>>> +        void (*fn)(const struct cpu_user_regs *) = (void *)regs-
>>>> BUG_FN_REG;
>>
>> ... this, wouldn't it be better (and independent of the specific
>> arch) if
>> you checked for BUG_FN_REG being defined?
> If I understand Kconfig correctly than there is no significant
> difference what check. But probably BUG_FN_REG would be a little bit
> better if someone will decide to change a way how pointer to function
> will be passed in case of ARM than we will get compilation error and so
> won't miss to fix the line in do_bug_frame().

Indeed - #ifdef like this one generally want to check for the precise
aspect in question, without making assumptions about something implying
something else. (Pretty certainly there are exceptions to this rule,
but it holds here.)

>>> +    ".p2align
>>> 2\n"                                                          \
>>> +   
>>> ".Lfrm%=:\n"                                                       
>>>      \
>>> +    ".long (.Lbug%= - .Lfrm%=) +
>>> %"MODIFIER"[bf_line_hi]\n"                  \
>>> +    ".long (%"MODIFIER"[bf_ptr] - .Lfrm%=) +
>>> %"MODIFIER"[bf_line_lo]\n"       \
>>> +    ".if " #second_frame
>>> "\n"                                               \
>>> +    ".long 0, %"MODIFIER"[bf_msg] -
>>> .Lfrm%=\n"                               \
>>> +   
>>> ".endif\n"                                                         
>>>      \
>>> +    ".popsection\n"
>>
>> I think I said so in reply to an earlier version already: The moment
>> assembly code moves to a common header, it should be adjusted to be
>> as
>> portable as possible. In particular directives should never start at
>> the
>> beginning of a line, while labels always should. (Whether .long is
>> actually portable is another question, which I'll be happy to leave
>> aside for now.)
> I am not sure that I understand about which one directive we are
> talking about... Are we talking about .{push/pop}section and .p2align?
> Probably you can show me an example in Xen or other project?

I'm talking about all directives here. Fundamentally assembly language
source lines are like this (assuming colons follow labels):

[<label>:|<blank>][<directive>|<insn>]

Both parts can optionally be empty, but if the right one isn't, then
the left one also shouldn't be (and hence minimally a blank is needed;
commonly it would be a tab). Directives, unlike insns, start with a
dot in most dialects. Labels can also start with a dot, but are
disambiguated by the colon after them (yet more strict placement of
items is therefore required when labels are not followed by colons -
there are such dialects -, which is why it is generally a good idea
to follow that simple formatting rule). Also, ftaod,
- <insn> covers both actual insns as well as assembler macro
  invocations,
- there can of course be multiple labels on a single line (iirc this
  requires that colons follow labels).

As to examples: I'm afraid I'm unaware of arch-independent assembly
code anywhere in Xen so far.

Jan
Oleksii Kurochko Feb. 23, 2023, 12:14 p.m. UTC | #4
On Thu, 2023-02-23 at 11:11 +0100, Jan Beulich wrote:
> On 22.02.2023 17:16, Oleksii wrote:
> > On Wed, 2023-02-22 at 13:46 +0100, Jan Beulich wrote:
> > > On 20.02.2023 17:40, Oleksii Kurochko wrote:
> > > > --- /dev/null
> > > > +++ b/xen/common/bug.c
> > > > @@ -0,0 +1,113 @@
> > > > +#include <xen/bug.h>
> > > > +#include <xen/errno.h>
> > > > +#include <xen/kernel.h>
> > > > +#include <xen/livepatch.h>
> > > > +#include <xen/string.h>
> > > > +#include <xen/types.h>
> > > > +#include <xen/virtual_region.h>
> > > > +
> > > > +#include <asm/processor.h>
> > > 
> > > Is this really needed here?
> > Yes, it is.
> > 
> > Function show_execution_state() is declared in this header for all
> > architectures and is used by handle_bug_frame().
> 
> Ugly, but yes, you're right.
> 
> > > > +const struct bug_frame* find_bug_frame(unsigned long pc,
> > > > unsigned
> > > > int *id)
> > > 
> > > Is this function going to be needed outside of this CU? IOW why
> > > is it
> > > not
> > > static?
> > > 
> > It's not static because there is not possible to use do_bug_frame()
> > as
> > is for x86 as x86 has some additional checks for some cases which
> > aren't in generic implementation:
> > [1]
> > https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1217
> > [2]
> > https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1238
> > [3]
> > https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/x86/traps.c#L1259
> > 
> > Probably to make generic do_bug_frame() more re-usable for x86 we
> > can
> > implement as stubs fixup_exception_return() and
> > debugger_trap_fatal()
> > under #ifndef X86 ... #endif inside common/bug.c.
> > 
> > Could you please share your thoughts about that?
> 
> Isn't all that's needed a suitable return value from the function,
> for the caller to take appropriate further action? (Maybe even that
> isn't really necessary.)
> 
> That said, debugger_trap_fatal() imo may sensibly be generalized,
> and hence could be left in common code. Arm may simply stub this to
> nothing then for the time being.
I checked the source code I found that debugger_trap_fatal() is
generalized:
https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/include/xen/debugger.h
So we can use in generic version of do_bug_frame().

About fixup_exception_return() you are right as we can it handle(call)
by the caller so it's needed only to return a suitable return value for
do_bug_frame().

> 
> > > > +{
> > > > +    const char *prefix = "", *filename, *predicate;
> > > > +    unsigned long fixup;
> > > > +    unsigned int lineno;
> > > > +
> > > > +    if ( id == BUGFRAME_run_fn )
> > > > +    {
> > > > +#ifdef ARM        
> > > 
> > > Who or what defines ARM? Anyway, seeing ...
> > it is defined by default in Kconfig:
> > https://gitlab.com/xen-project/people/olkur/xen/-/blob/staging/xen/arch/arm/Kconfig#L13
> 
> That'll be CONFIG_ARM then in uses in C code.
Ahh, yeah. I am always missing CONFIG_...
> 
> > > > +        void (*fn)(const struct cpu_user_regs *) = (void
> > > > *)regs-
> > > > > BUG_FN_REG;
> > > 
> > > ... this, wouldn't it be better (and independent of the specific
> > > arch) if
> > > you checked for BUG_FN_REG being defined?
> > If I understand Kconfig correctly than there is no significant
> > difference what check. But probably BUG_FN_REG would be a little
> > bit
> > better if someone will decide to change a way how pointer to
> > function
> > will be passed in case of ARM than we will get compilation error
> > and so
> > won't miss to fix the line in do_bug_frame().
> 
> Indeed - #ifdef like this one generally want to check for the precise
> aspect in question, without making assumptions about something
> implying
> something else. (Pretty certainly there are exceptions to this rule,
> but it holds here.)
Thanks for the explanation.
> 
> > > > +    ".p2align
> > > > 2\n"                                                          \
> > > > +   
> > > > ".Lfrm%=:\n"                                                   
> > > >     
> > > >      \
> > > > +    ".long (.Lbug%= - .Lfrm%=) +
> > > > %"MODIFIER"[bf_line_hi]\n"                  \
> > > > +    ".long (%"MODIFIER"[bf_ptr] - .Lfrm%=) +
> > > > %"MODIFIER"[bf_line_lo]\n"       \
> > > > +    ".if " #second_frame
> > > > "\n"                                               \
> > > > +    ".long 0, %"MODIFIER"[bf_msg] -
> > > > .Lfrm%=\n"                               \
> > > > +   
> > > > ".endif\n"                                                     
> > > >     
> > > >      \
> > > > +    ".popsection\n"
> > > 
> > > I think I said so in reply to an earlier version already: The
> > > moment
> > > assembly code moves to a common header, it should be adjusted to
> > > be
> > > as
> > > portable as possible. In particular directives should never start
> > > at
> > > the
> > > beginning of a line, while labels always should. (Whether .long
> > > is
> > > actually portable is another question, which I'll be happy to
> > > leave
> > > aside for now.)
> > I am not sure that I understand about which one directive we are
> > talking about... Are we talking about .{push/pop}section and
> > .p2align?
> > Probably you can show me an example in Xen or other project?
> 
> I'm talking about all directives here. Fundamentally assembly
> language
> source lines are like this (assuming colons follow labels):
> 
> [<label>:|<blank>][<directive>|<insn>]
> 
> Both parts can optionally be empty, but if the right one isn't, then
> the left one also shouldn't be (and hence minimally a blank is
> needed;
> commonly it would be a tab). Directives, unlike insns, start with a
> dot in most dialects. Labels can also start with a dot, but are
> disambiguated by the colon after them (yet more strict placement of
> items is therefore required when labels are not followed by colons -
> there are such dialects -, which is why it is generally a good idea
> to follow that simple formatting rule). Also, ftaod,
> - <insn> covers both actual insns as well as assembler macro
>   invocations,
> - there can of course be multiple labels on a single line (iirc this
>   requires that colons follow labels).
> 
> As to examples: I'm afraid I'm unaware of arch-independent assembly
> code anywhere in Xen so far.
Thank you very much for the explanation. 
> 
> Jan
~ Oleksii
Oleksii Kurochko Feb. 23, 2023, 1:16 p.m. UTC | #5
> 
> > +        void (*fn)(const struct cpu_user_regs *) = (void *)regs-
> > >BUG_FN_REG;
> 
> ... this, wouldn't it be better (and independent of the specific
> arch) if
> you checked for BUG_FN_REG being defined?
> 
> Another (#ifdef-free) variant would be to have bug_ptr() take a 2nd
> argument
> and then uniformly use ...
> 
> > +#else
> > +        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug);
> 
> ... this, slightly altered to
> 
>         void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug,
> regs);
I think that I will go with BUG_FN_REG instead of changing bug_ptr()'s
arguments as bug_ptr() is used below to get file name so it won't be
clear what bug_ptr() should return either an address of file name or
regs->BUG_FN_REG.
> 
> > +#endif
> > +
> > +        fn(regs);
> > +        return 0;
> > +    }
> > +
> > +    /* WARN, BUG or ASSERT: decode the filename pointer and line
> > number. */
> > +    filename = bug_ptr(bug);
> > +    if ( !is_kernel(filename) && !is_patch(filename) )
> 

~ Oleksii
Jan Beulich Feb. 23, 2023, 1:25 p.m. UTC | #6
On 23.02.2023 14:16, Oleksii wrote:
>>
>>> +        void (*fn)(const struct cpu_user_regs *) = (void *)regs-
>>>> BUG_FN_REG;
>>
>> ... this, wouldn't it be better (and independent of the specific
>> arch) if
>> you checked for BUG_FN_REG being defined?
>>
>> Another (#ifdef-free) variant would be to have bug_ptr() take a 2nd
>> argument
>> and then uniformly use ...
>>
>>> +#else
>>> +        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug);
>>
>> ... this, slightly altered to
>>
>>         void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug,
>> regs);
> I think that I will go with BUG_FN_REG instead of changing bug_ptr()'s
> arguments as bug_ptr() is used below to get file name so it won't be
> clear what bug_ptr() should return either an address of file name or
> regs->BUG_FN_REG.

Oh, indeed - I'm sorry that I didn't pay attention to ...

>>> +#endif
>>> +
>>> +        fn(regs);
>>> +        return 0;
>>> +    }
>>> +
>>> +    /* WARN, BUG or ASSERT: decode the filename pointer and line
>>> number. */
>>> +    filename = bug_ptr(bug);
>>> +    if ( !is_kernel(filename) && !is_patch(filename) )

... this 2nd use.

Jan
Jan Beulich Feb. 23, 2023, 1:32 p.m. UTC | #7
On 20.02.2023 17:40, Oleksii Kurochko wrote:
> --- /dev/null
> +++ b/xen/include/xen/bug.h
> @@ -0,0 +1,161 @@
> +#ifndef __XEN_BUG_H__
> +#define __XEN_BUG_H__
> +
> +#define BUG_DISP_WIDTH    24
> +#define BUG_LINE_LO_WIDTH (31 - BUG_DISP_WIDTH)
> +#define BUG_LINE_HI_WIDTH (31 - BUG_DISP_WIDTH)
> +
> +#define BUGFRAME_run_fn 0
> +#define BUGFRAME_warn   1
> +#define BUGFRAME_bug    2
> +#define BUGFRAME_assert 3
> +
> +#define BUGFRAME_NR     4
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <xen/errno.h>
> +#include <xen/lib.h>
> +#include <xen/stringify.h>
> +#include <xen/types.h>
> +
> +#include <asm/bug.h>

Looking at patch 2 onwards I came to wonder: How does that work without
you first removing stuff from the respective asm/bug.h (or adding
suitable #define-s to limit what gets defined below)? From all I can
tell the compiler should object to ...

> +#ifndef BUG_FRAME_STRUCT
> +
> +struct bug_frame {
> +    signed int loc_disp:BUG_DISP_WIDTH;
> +    unsigned int line_hi:BUG_LINE_HI_WIDTH;
> +    signed int ptr_disp:BUG_DISP_WIDTH;
> +    unsigned int line_lo:BUG_LINE_LO_WIDTH;
> +    signed int msg_disp[];
> +};

... this, as asm/bug.h will have declared such a struct already. The
#define-s further down may not be a problem if what they expand to
matches in both places, but that's then still a latent trap to fall
into.

Jan
Oleksii Kurochko Feb. 23, 2023, 3:09 p.m. UTC | #8
On Thu, 2023-02-23 at 14:32 +0100, Jan Beulich wrote:
> On 20.02.2023 17:40, Oleksii Kurochko wrote:
> > --- /dev/null
> > +++ b/xen/include/xen/bug.h
> > @@ -0,0 +1,161 @@
> > +#ifndef __XEN_BUG_H__
> > +#define __XEN_BUG_H__
> > +
> > +#define BUG_DISP_WIDTH    24
> > +#define BUG_LINE_LO_WIDTH (31 - BUG_DISP_WIDTH)
> > +#define BUG_LINE_HI_WIDTH (31 - BUG_DISP_WIDTH)
> > +
> > +#define BUGFRAME_run_fn 0
> > +#define BUGFRAME_warn   1
> > +#define BUGFRAME_bug    2
> > +#define BUGFRAME_assert 3
> > +
> > +#define BUGFRAME_NR     4
> > +
> > +#ifndef __ASSEMBLY__
> > +
> > +#include <xen/errno.h>
> > +#include <xen/lib.h>
> > +#include <xen/stringify.h>
> > +#include <xen/types.h>
> > +
> > +#include <asm/bug.h>
> 
> Looking at patch 2 onwards I came to wonder: How does that work
> without
> you first removing stuff from the respective asm/bug.h (or adding
> suitable #define-s to limit what gets defined below)? From all I can
> tell the compiler should object to ...
> 
> > +#ifndef BUG_FRAME_STRUCT
> > +
> > +struct bug_frame {
> > +    signed int loc_disp:BUG_DISP_WIDTH;
> > +    unsigned int line_hi:BUG_LINE_HI_WIDTH;
> > +    signed int ptr_disp:BUG_DISP_WIDTH;
> > +    unsigned int line_lo:BUG_LINE_LO_WIDTH;
> > +    signed int msg_disp[];
> > +};
> 
> ... this, as asm/bug.h will have declared such a struct already. The
> #define-s further down may not be a problem if what they expand to
> matches in both places, but that's then still a latent trap to fall
> into.
My fault. It doesn't work. I checked only RISC-V arch before and didn't
start all the test for patch 2...

So yeah, in patch 2 should be updated asm/bug.h headers with define
BUG_FRAME_STRUCT and remove all common parts [ BUG_DISP_WIDTH,
BUG_LINE_LO_WIDTH, BUG_LINE_HI_WIDTH, BUGFRAME_run_fn, BUGFRAME_warn,
BUGFRAME_bug, BUGFRAME_assert, BUGFRAME_NR,
{__start|__stop}_bug_frames{ | _{0-3} }[], ].

Thanks for noticing that.
> 
> Jan
~ Oleksii
diff mbox series

Patch

diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index f1ea3199c8..b226323537 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -28,6 +28,9 @@  config ALTERNATIVE_CALL
 config ARCH_MAP_DOMAIN_PAGE
 	bool
 
+config GENERIC_BUG_FRAME
+	bool
+
 config HAS_ALTERNATIVE
 	bool
 
diff --git a/xen/common/Makefile b/xen/common/Makefile
index bbd75b4be6..46049eac35 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -1,5 +1,6 @@ 
 obj-$(CONFIG_ARGO) += argo.o
 obj-y += bitmap.o
+obj-$(CONFIG_GENERIC_BUG_FRAME) += bug.o
 obj-$(CONFIG_HYPFS_CONFIG) += config_data.o
 obj-$(CONFIG_CORE_PARKING) += core_parking.o
 obj-y += cpu.o
diff --git a/xen/common/bug.c b/xen/common/bug.c
new file mode 100644
index 0000000000..5eab3ebb53
--- /dev/null
+++ b/xen/common/bug.c
@@ -0,0 +1,113 @@ 
+#include <xen/bug.h>
+#include <xen/errno.h>
+#include <xen/kernel.h>
+#include <xen/livepatch.h>
+#include <xen/string.h>
+#include <xen/types.h>
+#include <xen/virtual_region.h>
+
+#include <asm/processor.h>
+
+const struct bug_frame* find_bug_frame(unsigned long pc, unsigned int *id)
+{
+    const struct bug_frame *bug = NULL;
+    const struct virtual_region *region;
+
+    region = find_text_region(pc);
+    if ( region )
+    {
+        for ( *id = 0; *id < BUGFRAME_NR; (*id)++ )
+        {
+            const struct bug_frame *b;
+            unsigned int i;
+
+            for ( i = 0, b = region->frame[*id].bugs;
+                  i < region->frame[*id].n_bugs; b++, i++ )
+            {
+                if ( bug_loc(b) == pc )
+                {
+                    bug = b;
+                    goto found;
+                }
+            }
+        }
+    }
+
+ found:
+    return bug;
+}
+
+int handle_bug_frame(const struct cpu_user_regs *regs,
+                    const struct bug_frame *bug,
+                    unsigned int id)
+{
+    const char *prefix = "", *filename, *predicate;
+    unsigned long fixup;
+    unsigned int lineno;
+
+    if ( id == BUGFRAME_run_fn )
+    {
+#ifdef ARM        
+        void (*fn)(const struct cpu_user_regs *) = (void *)regs->BUG_FN_REG;
+#else
+        void (*fn)(const struct cpu_user_regs *) = bug_ptr(bug);
+#endif
+
+        fn(regs);
+        return 0;
+    }
+
+    /* WARN, BUG or ASSERT: decode the filename pointer and line number. */
+    filename = bug_ptr(bug);
+    if ( !is_kernel(filename) && !is_patch(filename) )
+        return -EINVAL;
+    fixup = strlen(filename);
+    if ( fixup > 50 )
+    {
+        filename += fixup - 47;
+        prefix = "...";
+    }
+    lineno = bug_line(bug);
+
+    switch ( id )
+    {
+    case BUGFRAME_warn:
+        printk("Xen WARN at %s%s:%d\n", prefix, filename, lineno);
+        show_execution_state(regs);
+        return 0;
+
+    case BUGFRAME_bug:
+        printk("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
+
+        show_execution_state(regs);
+        panic("Xen BUG at %s%s:%d\n", prefix, filename, lineno);
+
+    case BUGFRAME_assert:
+        /* ASSERT: decode the predicate string pointer. */
+        predicate = bug_msg(bug);
+        if ( !is_kernel(predicate) )
+            predicate = "<unknown>";
+
+        printk("Assertion '%s' failed at %s%s:%d\n",
+               predicate, prefix, filename, lineno);
+
+        show_execution_state(regs);
+        panic("Assertion '%s' failed at %s%s:%d\n",
+              predicate, prefix, filename, lineno);
+    }
+
+    return -EINVAL;
+}
+
+int do_bug_frame(const struct cpu_user_regs *regs, unsigned long pc)
+{
+    const struct bug_frame *bug = NULL;
+    unsigned int id;
+
+    bug = find_bug_frame(pc, &id);
+    if (!bug)
+        return -ENOENT;
+
+    return handle_bug_frame(regs, bug, id);
+}
+
diff --git a/xen/include/xen/bug.h b/xen/include/xen/bug.h
new file mode 100644
index 0000000000..4aedebeb18
--- /dev/null
+++ b/xen/include/xen/bug.h
@@ -0,0 +1,161 @@ 
+#ifndef __XEN_BUG_H__
+#define __XEN_BUG_H__
+
+#define BUG_DISP_WIDTH    24
+#define BUG_LINE_LO_WIDTH (31 - BUG_DISP_WIDTH)
+#define BUG_LINE_HI_WIDTH (31 - BUG_DISP_WIDTH)
+
+#define BUGFRAME_run_fn 0
+#define BUGFRAME_warn   1
+#define BUGFRAME_bug    2
+#define BUGFRAME_assert 3
+
+#define BUGFRAME_NR     4
+
+#ifndef __ASSEMBLY__
+
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/stringify.h>
+#include <xen/types.h>
+
+#include <asm/bug.h>
+
+#ifndef BUG_FRAME_STRUCT
+
+struct bug_frame {
+    signed int loc_disp:BUG_DISP_WIDTH;
+    unsigned int line_hi:BUG_LINE_HI_WIDTH;
+    signed int ptr_disp:BUG_DISP_WIDTH;
+    unsigned int line_lo:BUG_LINE_LO_WIDTH;
+    signed int msg_disp[];
+};
+
+#endif /* BUG_FRAME_STRUCT */
+
+#ifndef bug_loc
+#define bug_loc(b) ((unsigned long)(b) + (b)->loc_disp)
+#endif /* bug_loc */
+
+#ifndef bug_ptr
+#define bug_ptr(b) ((const void *)(b) + (b)->ptr_disp)
+#endif /* bug_ptr */
+
+#ifndef bug_line
+#define bug_line(b) (((((b)->line_hi + ((b)->loc_disp < 0)) &                \
+                       ((1 << BUG_LINE_HI_WIDTH) - 1)) <<                    \
+                      BUG_LINE_LO_WIDTH) +                                   \
+                     (((b)->line_lo + ((b)->ptr_disp < 0)) &                 \
+                      ((1 << BUG_LINE_LO_WIDTH) - 1)))
+#endif /* bug_line */
+
+#ifndef bug_msg
+#define bug_msg(b) ((const char *)(b) + (b)->msg_disp[1])
+#endif /* bug_msg */
+
+#ifndef _ASM_BUGFRAME_TEXT
+
+#define _ASM_BUGFRAME_TEXT(second_frame)                                    \
+    ".Lbug%=:"BUG_INSTR"\n"                                                 \
+    ".pushsection .bug_frames.%"MODIFIER"[bf_type], \"a\", @progbits\n"      \
+    ".p2align 2\n"                                                          \
+    ".Lfrm%=:\n"                                                            \
+    ".long (.Lbug%= - .Lfrm%=) + %"MODIFIER"[bf_line_hi]\n"                  \
+    ".long (%"MODIFIER"[bf_ptr] - .Lfrm%=) + %"MODIFIER"[bf_line_lo]\n"       \
+    ".if " #second_frame "\n"                                               \
+    ".long 0, %"MODIFIER"[bf_msg] - .Lfrm%=\n"                               \
+    ".endif\n"                                                              \
+    ".popsection\n"
+
+#endif /* _ASM_BUGFRAME_TEXT */
+
+#ifndef _ASM_BUGFRAME_INFO
+
+#define _ASM_BUGFRAME_INFO(type, line, ptr, msg)                             \
+    [bf_type]    "i" (type),                                                 \
+    [bf_ptr]     "i" (ptr),                                                  \
+    [bf_msg]     "i" (msg),                                                  \
+    [bf_line_lo] "i" ((line & ((1 << BUG_LINE_LO_WIDTH) - 1))                \
+                      << BUG_DISP_WIDTH),                                    \
+    [bf_line_hi] "i" (((line) >> BUG_LINE_LO_WIDTH) << BUG_DISP_WIDTH)
+
+#endif /* _ASM_BUGFRAME_INFO */
+
+#ifndef BUG_FRAME
+
+#define BUG_FRAME(type, line, ptr, second_frame, msg) do {                   \
+    BUILD_BUG_ON((line) >> (BUG_LINE_LO_WIDTH + BUG_LINE_HI_WIDTH));         \
+    BUILD_BUG_ON((type) >= BUGFRAME_NR);                                     \
+    asm volatile ( _ASM_BUGFRAME_TEXT(second_frame)                          \
+                   :: _ASM_BUGFRAME_INFO(type, line, ptr, msg) );            \
+} while (0)
+
+#endif
+
+#ifndef run_in_exception_handler
+
+/*
+ * TODO: untangle header dependences, break BUILD_BUG_ON() out of xen/lib.h,
+ * and use a real static inline here to get proper type checking of fn().
+ */
+#define run_in_exception_handler(fn)                            \
+    do {                                                        \
+        (void)((fn) == (void (*)(struct cpu_user_regs *))NULL); \
+        BUG_FRAME(BUGFRAME_run_fn, 0, fn, 0, NULL);             \
+    } while ( 0 )
+
+#endif /* run_in_exception_handler */
+
+#ifndef WARN
+#define WARN() BUG_FRAME(BUGFRAME_warn, __LINE__, __FILE__, 0, NULL)
+#endif /* WARN */
+
+#ifndef BUG
+#define BUG() do {                                              \
+    BUG_FRAME(BUGFRAME_bug,  __LINE__, __FILE__, 0, NULL);      \
+    unreachable();                                              \
+} while (0)
+#endif
+
+#ifndef assert_failed
+#define assert_failed(msg) do {                                 \
+    BUG_FRAME(BUGFRAME_assert, __LINE__, __FILE__, 1, msg);     \
+    unreachable();                                              \
+} while (0)
+#endif
+
+#ifdef CONFIG_GENERIC_BUG_FRAME
+
+struct cpu_user_regs;
+
+const struct bug_frame* find_bug_frame(unsigned long pc, unsigned int *id);
+
+int handle_bug_frame(const struct cpu_user_regs *regs,
+                    const struct bug_frame *bug,
+                    unsigned int id);
+
+int do_bug_frame(const struct cpu_user_regs *regs, unsigned long pc);
+
+#endif /* CONFIG_GENERIC_BUG_FRAME */
+
+extern const struct bug_frame __start_bug_frames[],
+                              __stop_bug_frames_0[],
+                              __stop_bug_frames_1[],
+                              __stop_bug_frames_2[],
+                              __stop_bug_frames_3[];
+
+#else /* !__ASSEMBLY__ */
+
+#include <asm/bug.h>
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __XEN_BUG_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */