1

I'm new to qemu and trying to run riscv binaries in user mode. Not sure if I'm running into a bug or just doing something wrong. System I'm using is pretty straightforward Fedora 35 on x86_64.

For reference, C++ hello world works fine for mipsel using prebuilt toolchain from musl.cc.

$ cat hello.cc
#include <iostream>
int main() {
 std::cout << "Hello\n";
 return 0;
}
$ mipsel-linux-musl-g++ -static -g -O0 hello.cc -o hello
$ qemu-mipsel hello
Hello

Likewise for C with riscv (32 or 64 doesn't seem to matter).

$ cat hello.c
#include<stdio.h>
int main(int argc, char **argv) {
 printf("Hello\n");
 return 0;
}
$ riscv32-linux-musl-gcc -static -g -Og hello.c -o hello
$ qemu-riscv32 hello
Hello

But for C++/riscv I get a segfault.

$ riscv32-linux-musl-g++ -static -g -Og hello.cc -o hello
$ qemu-riscv32 hello
Segmentation fault (core dumped)

Apparently coming from qemu itself

Thread 1 "qemu-riscv32" received signal SIGSEGV, Segmentation fault.
0x00007fffe802558e in code_gen_buffer ()
(gdb) bt
#0  0x00007fffe802558e in code_gen_buffer ()
#1  0x00005555556bb44e in cpu_tb_exec (cpu=0x555555887b50, itb=<optimized out>, tb_exit=0x7fffffffd9a0) at ../accel/tcg/cpu-exec.c:353
#2  0x00005555556bc2f9 in cpu_loop_exec_tb (tb_exit=0x7fffffffd9a0, last_tb=<synthetic pointer>, tb=0x7fffe8025500 <code_gen_buffer+152787>, cpu=0x555555887b50)
    at ../accel/tcg/cpu-exec.c:812
#3  cpu_exec (cpu=cpu@entry=0x555555887b50) at ../accel/tcg/cpu-exec.c:970
#4  0x00005555555eed28 in cpu_loop (env=0x55555588fe40) at ../linux-user/riscv/cpu_loop.c:37
#5  0x00005555555e2b81 in main (argc=<optimized out>, argv=0x7fffffffe1c8, envp=<optimized out>) at ../linux-user/main.c:885

Something similar happens in system emulation mode for riscv64 as well.

I'm happy to report this as a qemu bug, but it seems more likely that I'm just doing something wrong. Am I doing something wrong?

Update:

I attached to the gdb stub and the segfault happens on a dynamic cast in the binary:

(gdb) bt
#0  __cxxabiv1::__dynamic_cast (src_ptr=0x40000e19e0 <(anonymous namespace)::ctype_c>, src_type=0x40000d8808 <typeinfo for std::locale::facet>, dst_type=0x40000d9ac0 <typeinfo for std::ctype<char>>, src2dst=0)
    at ../../../../src_gcc/libstdc++-v3/libsupc++/dyncast.cc:74
#1  0x000000400005ed58 in std::has_facet<std::ctype<char> > (__loc=...) at /tmp/m1132/build/local/riscv64-linux-musl/obj_gcc/riscv64-linux-musl/libstdc++-v3/include/bits/locale_classes.tcc:110
#2  0x0000004000054be0 in std::basic_ios<char, std::char_traits<char> >::_M_cache_locale (this=this@entry=0x40000e0af8 <std::cout+8>, __loc=...)
    at /tmp/m1132/build/local/riscv64-linux-musl/obj_gcc/riscv64-linux-musl/libstdc++-v3/include/bits/basic_ios.tcc:159
#3  0x0000004000054eaa in std::basic_ios<char, std::char_traits<char> >::init (this=this@entry=0x40000e0af8 <std::cout+8>, __sb=__sb@entry=0x40000e00d8 <__gnu_internal::buf_cout_sync>)
    at /tmp/m1132/build/local/riscv64-linux-musl/obj_gcc/riscv64-linux-musl/libstdc++-v3/include/bits/basic_ios.tcc:132
#4  0x0000004000027ad2 in std::basic_ostream<char, std::char_traits<char> >::basic_ostream (__sb=<optimized out>, this=<optimized out>, __in_chrg=<optimized out>, __vtt_parm=<optimized out>)
    at /tmp/m1132/build/local/riscv64-linux-musl/obj_gcc/riscv64-linux-musl/libstdc++-v3/include/ostream:85
#5  std::ios_base::Init::Init (this=<optimized out>) at ../../../../../src_gcc/libstdc++-v3/src/c++98/ios_init.cc:91
#6  std::ios_base::Init::Init (this=<optimized out>) at ../../../../../src_gcc/libstdc++-v3/src/c++98/ios_init.cc:78
#7  0x00000040000278c0 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at /home/jpkenny/src/riscv64-linux-musl-cross/riscv64-linux-musl/include/c++/11.2.1/iostream:74
#8  0x00000040000278fa in _GLOBAL__sub_I_main () at hello.cc:5
#9  0x000000400008fbfa in libc_start_init ()
Backtrace stopped: frame did not save the PC

According to gdb, this occurs on the last asm instruction here:

000000000007d38e <__dynamic_cast>:
   7d38e:       c55d                    beqz    a0,7d43c <__dynamic_cast+0xae>
   7d390:       00053803                ld      a6,0(a0)
   7d394:       715d                    addi    sp,sp,-80
   7d396:       fc26                    sd      s1,56(sp)
   7d398:       ff083703                ld      a4,-16(a6)
   7d39c:       ff883783                ld      a5,-8(a6)
   7d3a0:       84b6                    mv      s1,a3
   7d3a2:       972a                    add     a4,a4,a0
   7d3a4:       6314                    ld      a3,0(a4)
   7d3a6:       4805                    li      a6,1
   7d3a8:       1812                    slli    a6,a6,0x24
   7d3aa:       e802                    sd      zero,16(sp)
   7d3ac:       ec42                    sd      a6,24(sp)
   7d3ae:       e0a2                    sd      s0,64(sp)
   7d3b0:       842a                    mv      s0,a0
   7d3b2:       ff86b503                ld      a0,-8(a3)
   7d3b6:       e486                    sd      ra,72(sp)
   7d3b8:       f84a                    sd      s2,48(sp)
   7d3ba:       f44e                    sd      s3,40(sp)
   7d3bc:       f052                    sd      s4,32(sp)
   7d3be:       e402                    sd      zero,8(sp)
   7d3c0:       04f51663                bne     a0,a5,7d40c <__dynamic_cast+0x7e>
   7d3c4:       611c                    ld      a5,0(a0)
RickySmith
  • 11
  • 3
  • You don't say what QEMU version you're using. If it's not the latest, try the latest. Also, if you have access to riscv hardware, checking your test binary runs there is a good cross-check. – Peter Maydell Mar 11 '22 at 10:21
  • I see this behavior with both the qemu 6.1.0 yum package and building 6.2.0 (latest) from source. I don't have access to riscv hardware. I searched the qemu issue tracker and didn't see any similar issues. This seems like pretty basic functionality that I wouldn't be the first person to come across. Perhaps I should just file a bug report and see. – RickySmith Mar 11 '22 at 16:29
  • SEGV in code_gen_buffer for user-mode QEMU generally means "the guest segfaulted", incidentally (QEMU directly translates guest load/store insns into host ones, so if the guest does something that from its point of view should segfault then it will turn into a segfault in the generated load/store insn in the code gen buffer. You might try connecting a gdb to the QEMU gdbstub to see what guest insn is faulting. – Peter Maydell Mar 13 '22 at 17:40
  • @PeterMaydell Thanks for the very useful info. I was able to sort out the guest debugging and edited the question to include the backtrace and asm. I'm not very knowledgeable with assembly (yeah, looks like it's time to learn). Any ideas what's happening? – RickySmith Mar 15 '22 at 01:19

0 Answers0