Re: A reliable port cross-build failure (hangup) in my context (amd64->armv7 cross build, with native-tool speedup involved) [details of a specific qemu-arm-static source code problem]

From: Mark Millard <marklmi_at_yahoo.com>
Date: Sun, 30 Dec 2018 17:26:01 -0800
[Removing __packed did make the size and offsets match armv7
and the build worked based on the reconstructed qemu-arm-static.]

On 2018-Dec-30, at 16:38, Mark Millard <marklmi_at_yahoo.com> wrote:

> On 2018-Dec-28, at 12:12, Mark Millard <marklmi at yahoo.com> wrote:
> 
>> On 2018-Dec-28, at 05:13, Michal Meloun <melounmichal at gmail.com> wrote:
>> 
>>> Mark,
>>> this is known problem with qemu-user-static.
>>> Emulation of every single interruptible syscall is broken by design (it
>>> have signal related races). Theses races cannot be solved without major
>>> rewrite of syscall emulation code.
>>> Unfortunately, nobody actively works on this, I think.
>>> 
>> 
>> Thanks for the note setting some expectations.
>> . . .
> 
> 
> It turns out that I've been through (part of?) this before and
> mikael.urankar_at_gmail.com had back then provided a qemu-user-static
> patch (that might have been arm specific or 32-bit target specific
> when running on a 64-bit host). (The qemu-user-static code structure
> seems to have changed some afterwards and the patch is no longer
> where he had pointed me to back then.)
> 
> To show size and offsets on armv7 vs. armd64 for struct kevent
> I use:
> 
> # more kevent_size_offsets.c 
> #include "/usr/include/sys/event.h" // kevent
> #include <stddef.h> // offsetof
> #include <stdio.h>  // printf
> 
> int
> main()
> {
>        printf("%lu\n", (unsigned long) sizeof(struct kevent));
>        printf("ident %lu\n", (unsigned long) offsetof(struct kevent, ident));
>        printf("filter %lu\n", (unsigned long) offsetof(struct kevent, filter));
>        printf("flags %lu\n", (unsigned long) offsetof(struct kevent, flags));
>        printf("fflags %lu\n", (unsigned long) offsetof(struct kevent, fflags));
>        printf("data %lu\n", (unsigned long) offsetof(struct kevent, data));
>        printf("udata %lu\n", (unsigned long) offsetof(struct kevent, udata));
>        printf("ext %lu\n", (unsigned long) offsetof(struct kevent, ext));
>        return 0;
> }
> 
> It ends up showing on armv7 (under qemu-arm-static insteead of native, not
> that it matters here):
> 
> # ./a.out
> 64
> ident 0
> filter 4
> flags 6
> fflags 8
> data 16
> udata 24
> ext 32
> 
> On amd64 (native) it ends up as:
> 
> # ./a.out
> 64
> ident 0
> filter 8
> flags 10
> fflags 12
> data 16
> udata 24
> ext 32
> 
> Thus a translation of layout is required when hosted. This is for:
> 
> struct kevent {
>        __uintptr_t     ident;          /* identifier for this event */
>        short           filter;         /* filter for event */
>        unsigned short  flags;          /* action flags for kqueue */
>        unsigned int    fflags;         /* filter flag value */
>        __int64_t       data;           /* filter data value */
>        void            *udata;         /* opaque user data identifier */
>        __uint64_t      ext[4];         /* extensions */
> };
> 
> But qemu-user-static has for translation purposes:
> 
> struct target_freebsd_kevent {
>    abi_ulong  ident;
>    int16_t    filter;
>    uint16_t   flags;
>    uint32_t   fflags;
>    int64_t data;
>    abi_ulong  udata;
>    uint64_t  ext[4];
> } __packed;
> 
> (note the __packed) for which in amd64's qemu_arm_static has
> the size and offsets:
> 
> # gdb qemu-arm-static
> . . .
> (gdb) p/d sizeof(struct target_freebsd_kevent)
> $1 = 56
> (gdb) p/d &((struct target_freebsd_kevent *)0)->ident
> $2 = 0
> (gdb) p/d &((struct target_freebsd_kevent *)0)->filter
> $3 = 4
> (gdb) p/d &((struct target_freebsd_kevent *)0)->flags
> $4 = 6
> (gdb) p/d &((struct target_freebsd_kevent *)0)->fflags
> $5 = 8
> (gdb) p/d &((struct target_freebsd_kevent *)0)->data
> $6 = 12
> (gdb) p/d &((struct target_freebsd_kevent *)0)->udata
> $7 = 20
> (gdb) p/d &((struct target_freebsd_kevent *)0)->ext
> $8 = 24
> 
> which which does not match the armv7 offsets for
> data, udata, or ext and does not have the right size
> for struct target_freebsd_kevent[] indexing to
> match armv7's struct target_freebsd_kevent[] indexing.
> 
> This in turn makes the do_freebsd_kevent code do the wrong
> thing in its:
> 
>    struct target_freebsd_kevent *target_changelist, *target_eventlist;
> . . .
>        for (i = 0; i < arg3; i++) {
>            __get_user(changelist[i].ident, &target_changelist[i].ident);
>            __get_user(changelist[i].filter, &target_changelist[i].filter);
>            __get_user(changelist[i].flags, &target_changelist[i].flags);
>            __get_user(changelist[i].fflags, &target_changelist[i].fflags);
>            __get_user(changelist[i].data, &target_changelist[i].data);
>            /* __get_user(changelist[i].udata, &target_changelist[i].udata); */
> #if TARGET_ABI_BITS == 32
>            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
>            tswap32s((uint32_t *)&changelist[i].udata);
> #else
>            changelist[i].udata = (void *)(uintptr_t)target_changelist[i].udata;
>            tswap64s((uint64_t *)&changelist[i].udata);
> #endif
>            __get_user(changelist[i].ext[0], &target_changelist[i].ext[0]);
>            __get_user(changelist[i].ext[1], &target_changelist[i].ext[1]);
>            __get_user(changelist[i].ext[2], &target_changelist[i].ext[2]);
>            __get_user(changelist[i].ext[3], &target_changelist[i].ext[3]);
>        }
> . . .
>        for (i = 0; i < arg5; i++) {
>            __put_user(eventlist[i].ident, &target_eventlist[i].ident);
>            __put_user(eventlist[i].filter, &target_eventlist[i].filter);
>            __put_user(eventlist[i].flags, &target_eventlist[i].flags);
>            __put_user(eventlist[i].fflags, &target_eventlist[i].fflags);
>            __put_user(eventlist[i].data, &target_eventlist[i].data);
>            /* __put_user(eventlist[i].udata, &target_eventlist[i].udata);*/
> #if TARGET_ABI_BITS == 32
>            tswap32s((uint32_t *)&eventlist[i].data);
>            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
> #else
>            tswap64s((uint64_t *)&eventlist[i].data);
>            target_eventlist[i].data = (uintptr_t)eventlist[i].data;
> #endif
>            __put_user(eventlist[i].ext[0], &target_eventlist[i].ext[0]);
>            __put_user(eventlist[i].ext[1], &target_eventlist[i].ext[1]);
>            __put_user(eventlist[i].ext[2], &target_eventlist[i].ext[2]);
>            __put_user(eventlist[i].ext[3], &target_eventlist[i].ext[3]);
>        }
> 
> 
> 
> I'll eventually do something to have struct target_freebsd_kevent for
> amd64-native targeting armv7 and see if that is sufficient to avoid the
> problem in my context. Previously removing the __packed was enough to
> make the structure the same size with the same offsets as for armv7.
> (Such might not have been appropriate to all targets.)
> 
> armv6 would have the same problem as I understand things.


Using commented out __packed in:

struct target_freebsd11_kevent {
    abi_ulong  ident;
    int16_t    filter;
    uint16_t   flags;
    uint32_t   fflags;
    abi_long   data;
    abi_ulong  udata;
} ; // __packed;

struct target_freebsd_kevent {
    abi_ulong  ident;
    int16_t    filter;
    uint16_t   flags;
    uint32_t   fflags;
    int64_t data;
    abi_ulong  udata;
    uint64_t  ext[4];
} ; // __packed;


in /wrkdirs/usr/ports/emulators/qemu-user-static/work/qemu-bsd-user-4ef7d07/bsd-user/syscall_defs.h
was sufficient to allow the multimedia/gstreamer1-qt_at_qt5 build to complete: no more hang-up.

So this is likely what is wrong for the packages-builders as well.


===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)
Received on Mon Dec 31 2018 - 00:26:16 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:41:19 UTC