You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(83) |
Oct
(89) |
Nov
(97) |
Dec
(30) |
2024 |
Jan
(25) |
Feb
(73) |
Mar
(76) |
Apr
(122) |
May
(46) |
Jun
(44) |
Jul
(27) |
Aug
(30) |
Sep
(33) |
Oct
(67) |
Nov
(91) |
Dec
(70) |
2025 |
Jan
(44) |
Feb
(36) |
Mar
(85) |
Apr
(100) |
May
(138) |
Jun
(55) |
Jul
(107) |
Aug
(27) |
Sep
|
Oct
|
Nov
|
Dec
|
From: Paul F. <pa...@so...> - 2025-03-08 08:23:26
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=df5c62e04c26c328276e78fcb3923d5508fb70b8 commit df5c62e04c26c328276e78fcb3923d5508fb70b8 Author: Paul Floyd <pj...@wa...> Date: Sat Mar 8 09:20:53 2025 +0100 Fix int to pointer warnings and a minnor correction for a comment about ELF segment handling Diff: --- VEX/priv/host_riscv64_defs.c | 10 +++++----- coregrind/m_debuginfo/readelf.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/VEX/priv/host_riscv64_defs.c b/VEX/priv/host_riscv64_defs.c index f6137b55bc..6296b2e7fe 100644 --- a/VEX/priv/host_riscv64_defs.c +++ b/VEX/priv/host_riscv64_defs.c @@ -2353,7 +2353,7 @@ Int emit_RISCV64Instr(/*MB_MOD*/ Bool* is_profInc, ? disp_cp_chain_me_to_fastEP : disp_cp_chain_me_to_slowEP; - p = addr48_to_ireg_EXACTLY_18B(p, 5 /*x5/t0*/, (ULong)disp_cp_chain_me); + p = addr48_to_ireg_EXACTLY_18B(p, 5 /*x5/t0*/, (ULong)(HWord)disp_cp_chain_me); /* c.jalr 0(t0) */ p = emit_CR(p, 0b10, 0 /*x0/zero*/, 5 /*x5/t0*/, 0b1001); @@ -2405,7 +2405,7 @@ Int emit_RISCV64Instr(/*MB_MOD*/ Bool* is_profInc, } /* li t0, VG_(disp_cp_xindir) */ - p = imm64_to_ireg(p, 5 /*x5/t0*/, (ULong)disp_cp_xindir); + p = imm64_to_ireg(p, 5 /*x5/t0*/, (ULong)(HWord)disp_cp_xindir); /* c.jr 0(t0) */ p = emit_CR(p, 0b10, 0 /*x0/zero*/, 5 /*x5/t0*/, 0b1000); @@ -2479,7 +2479,7 @@ Int emit_RISCV64Instr(/*MB_MOD*/ Bool* is_profInc, p = imm64_to_ireg(p, 8 /*x8/s0*/, trcval); /* li t0, VG_(disp_cp_xassisted) */ - p = imm64_to_ireg(p, 5 /*x5/t0*/, (ULong)disp_cp_xassisted); + p = imm64_to_ireg(p, 5 /*x5/t0*/, (ULong)(HWord)disp_cp_xassisted); /* c.jr 0(t0) */ p = emit_CR(p, 0b10, 0 /*x0/zero*/, 5 /*x5/t0*/, 0b1000); @@ -2598,7 +2598,7 @@ VexInvalRange chainXDirect_RISCV64(VexEndness endness_host, UChar* p = place_to_chain; vassert(((HWord)p & 1) == 0); vassert(is_addr48_to_ireg_EXACTLY_18B(p, 5 /*x5/t0*/, - (ULong)disp_cp_chain_me_EXPECTED)); + (ULong)(HWord)disp_cp_chain_me_EXPECTED)); vassert(p[18] == 0x82 && p[19] == 0x92); /* And what we want to change it to is: @@ -2615,7 +2615,7 @@ VexInvalRange chainXDirect_RISCV64(VexEndness endness_host, The replacement has the same length as the original. */ - (void)addr48_to_ireg_EXACTLY_18B(p, 5 /*x5/t0*/, (ULong)place_to_jump_to); + (void)addr48_to_ireg_EXACTLY_18B(p, 5 /*x5/t0*/, (ULong)(HWord)place_to_jump_to); p[18] = 0x82; p[19] = 0x82; diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index 1dadbc72c5..0c37ea1009 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -3939,7 +3939,7 @@ Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, * VG_(di_notify_mmap): in some cases, the 2 NSegments will * have been merged and VG_(di_notify_mmap) only gets called * once. - * How to detect that the segments were be merged ? + * How to detect that the segments were merged ? * Logically, they will be merged if the first segment ends * at the beginning of the second segment: * Seg1 virtual address + Seg1 segment_size |
From: Paul F. <pa...@so...> - 2025-03-07 22:12:46
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=6999f18906f0b16d407eda3a9975cb3845dedcfe commit 6999f18906f0b16d407eda3a9975cb3845dedcfe Author: Paul Floyd <pj...@wa...> Date: Fri Mar 7 23:12:13 2025 +0100 Bug 501194 - Fix ML_(check_macho_and_get_rw_loads) so that it is correct for any number of segment commands Diff: --- NEWS | 1 + coregrind/m_debuginfo/debuginfo.c | 39 +++------------------------------- coregrind/m_debuginfo/priv_readmacho.h | 2 +- coregrind/m_debuginfo/readmacho.c | 33 +++++++++++++++++----------- 4 files changed, 26 insertions(+), 49 deletions(-) diff --git a/NEWS b/NEWS index 304ce1c0b7..0fcbc5d0e2 100644 --- a/NEWS +++ b/NEWS @@ -56,6 +56,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 498492 none/tests/amd64/lzcnt64 crashes on FreeBSD compiled with clang 499183 FreeBSD: differences in avx-vmovq output 499212 mmap() with MAP_ALIGNED() returns unaligned pointer +501194 Fix ML_(check_macho_and_get_rw_loads) so that it is correct for any number of segment commands To see details of a given bug, visit diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index 97d0f35c05..612833a997 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -1135,16 +1135,6 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) DebugInfo* di; Int actual_fd, oflags; -#if defined(VGO_darwin) - SysRes preadres; - // @todo PJF make this dynamic - // that probably means reading the sizeofcmds from the mach_header then - // allocating enough space for it - // and then one day maybe doing something for fat binaries - HChar buf4k[4096]; -#else - Bool elf_ok; -#endif #if defined(VGO_freebsd) static Bool first_fixed_file = True; #endif @@ -1321,11 +1311,6 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) } #endif -#if defined(VGO_darwin) - /* Peer at the first few bytes of the file, to see if it is an ELF */ - /* object file. Ignore the file if we do not have read permission. */ - VG_(memset)(buf4k, 0, sizeof(buf4k)); -#endif oflags = VKI_O_RDONLY; # if defined(VKI_O_LARGEFILE) @@ -1350,35 +1335,17 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) actual_fd = use_fd; } -#if defined(VGO_darwin) - preadres = VG_(pread)( actual_fd, buf4k, sizeof(buf4k), 0 ); - if (use_fd == -1) { - VG_(close)( actual_fd ); - } - - if (sr_isError(preadres)) { - DebugInfo fake_di; - VG_(memset)(&fake_di, 0, sizeof(fake_di)); - fake_di.fsm.filename = ML_(dinfo_strdup)("di.debuginfo.nmm", filename); - ML_(symerr)(&fake_di, True, "can't read file to inspect Mach-O headers"); - return 0; - } - if (sr_Res(preadres) == 0) - return 0; - vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf4k) ); - expected_rw_load_count = 0; - if (!ML_(check_macho_and_get_rw_loads)( buf4k, (SizeT)sr_Res(preadres), &expected_rw_load_count )) +#if defined(VGO_darwin) + if (!ML_(check_macho_and_get_rw_loads)( actual_fd, &expected_rw_load_count )) return 0; #endif /* We're only interested in mappings of object files. */ # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) - expected_rw_load_count = 0; - - elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &expected_rw_load_count, use_fd == -1 ); + Bool elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &expected_rw_load_count, use_fd == -1 ); if (use_fd == -1) { VG_(close)( actual_fd ); diff --git a/coregrind/m_debuginfo/priv_readmacho.h b/coregrind/m_debuginfo/priv_readmacho.h index b5172878ce..0cbdad90f2 100644 --- a/coregrind/m_debuginfo/priv_readmacho.h +++ b/coregrind/m_debuginfo/priv_readmacho.h @@ -35,7 +35,7 @@ /* Identify a Mach-O object file by peering at the first few bytes of it. Also count the number of RW segements. */ -extern Bool ML_(check_macho_and_get_rw_loads)( const void* buf, SizeT size, Int* rw_loads ); +extern Bool ML_(check_macho_and_get_rw_loads)( Int fd, Int* rw_loads ); /* The central function for reading Mach-O debug info. For the object/exe specified by the DebugInfo, find Mach-O sections, then read diff --git a/coregrind/m_debuginfo/readmacho.c b/coregrind/m_debuginfo/readmacho.c index e93bae7941..691ec94353 100644 --- a/coregrind/m_debuginfo/readmacho.c +++ b/coregrind/m_debuginfo/readmacho.c @@ -93,7 +93,7 @@ memory that falls entirely inside the primary image. */ -Bool ML_(check_macho_and_get_rw_loads)( const void* buf, SizeT szB, Int* rw_loads ) +Bool ML_(check_macho_and_get_rw_loads)( Int fd, Int* rw_loads ) { /* (JRS: the Mach-O headers might not be in this mapped data, because we only mapped a page for this initial check, @@ -108,27 +108,35 @@ Bool ML_(check_macho_and_get_rw_loads)( const void* buf, SizeT szB, Int* rw_load can to establish whether or not we're looking at something sane. */ - /* @todo PJF change function signature to pass in file handle - Read MACH_HEADER to determine sizeofcommands - Allocate a dynamic buffer for the commands. */ + HChar macho_header[sizeof(struct MACH_HEADER)]; + SysRes preadres = VG_(pread)( fd, macho_header, sizeof(struct MACH_HEADER), 0 ); - const struct fat_header* fh_be = buf; - const struct MACH_HEADER* mh = buf; + if (sr_isError(preadres) || sr_Res(preadres) < sizeof(struct MACH_HEADER)) { + return False; + } - vg_assert(buf); + const struct fat_header* fh_be = (const struct fat_header*)macho_header; + const struct MACH_HEADER* mh = (const struct MACH_HEADER*)macho_header; + + vg_assert(fh_be); + vg_assert(mh); vg_assert(rw_loads); - if (szB < sizeof(struct fat_header)) - return False; + STATIC_ASSERT(sizeof(struct fat_header) <= sizeof(struct MACH_HEADER)); if (VG_(ntohl)(fh_be->magic) == FAT_MAGIC) { // @todo PJF not yet handled, previous behaviour was to assume that the count is 1 *rw_loads = 1; return True; } - if (szB < sizeof(struct MACH_HEADER)) - return False; if (mh->magic == MAGIC) { - const struct load_command* lc = (const struct load_command*)((const char*)buf + sizeof(struct MACH_HEADER)); + HChar* macho_load_commands = ML_(dinfo_zalloc)("di.readmacho.macho_load_commands", mh->sizeofcmds); + preadres = VG_(pread)( fd, macho_load_commands, mh->sizeofcmds, sizeof(struct MACH_HEADER) ); + if (sr_isError(preadres) || sr_Res(preadres) < mh->sizeofcmds) { + ML_(dinfo_free)(macho_load_commands); + return False; + } + + const struct load_command* lc = (const struct load_command*)macho_load_commands; for (unsigned int i = 0U; i < mh->ncmds; ++i) { if (lc->cmd == LC_SEGMENT_CMD) { const struct SEGMENT_COMMAND* sc = (const struct SEGMENT_COMMAND*)lc; @@ -139,6 +147,7 @@ Bool ML_(check_macho_and_get_rw_loads)( const void* buf, SizeT szB, Int* rw_load const char* tmp = (const char*)lc + lc->cmdsize; lc = (const struct load_command*)tmp; } + ML_(dinfo_free)(macho_load_commands); return True; } |
From: Paul F. <pa...@so...> - 2025-03-07 06:03:27
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=081baa136cc905dc1abb57e14565df597dcb1b6b commit 081baa136cc905dc1abb57e14565df597dcb1b6b Author: Paul Floyd <pj...@wa...> Date: Fri Mar 7 07:00:26 2025 +0100 FreeBSD regtest: getrlimitusage on arm64 Resident memory isn't stable even when truncated to a multiple of ten milllion. I.e., zero digits of useful precision. So just set this field to zero like the other flaky values. Diff: --- memcheck/tests/freebsd/getrlimitusage.c | 5 ++--- memcheck/tests/freebsd/getrlimitusage.stderr.exp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/memcheck/tests/freebsd/getrlimitusage.c b/memcheck/tests/freebsd/getrlimitusage.c index b601dfdb58..5b73479012 100644 --- a/memcheck/tests/freebsd/getrlimitusage.c +++ b/memcheck/tests/freebsd/getrlimitusage.c @@ -82,9 +82,11 @@ int main(int argc, char *argv[]) } } // add some rounding to try to make regtest stable + // most of these change all the time switch (i) { case 7: + case 5: case 9: case 11: case 12: @@ -93,9 +95,6 @@ int main(int argc, char *argv[]) case 15: res = 0U; break; - case 5: - res = res/10000000 * 10000000; - break; case 10: res = res/100000000 * 100000000; break; diff --git a/memcheck/tests/freebsd/getrlimitusage.stderr.exp b/memcheck/tests/freebsd/getrlimitusage.stderr.exp index a5b5f33bb2..1923e27ce6 100644 --- a/memcheck/tests/freebsd/getrlimitusage.stderr.exp +++ b/memcheck/tests/freebsd/getrlimitusage.stderr.exp @@ -3,7 +3,7 @@ fsize (1): -1 data (2): 4096 stack (3): 16777216 core (4): -1 -rss (5): 40000000 +rss (5): 0 memlock (6): 0 nproc (7): 0 nofile (8): 3 |
From: Florian K. <fk...@so...> - 2025-03-06 18:41:12
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=ec0c87aebf6b56d582b63d873e55a4274b0b6b41 commit ec0c87aebf6b56d582b63d873e55a4274b0b6b41 Author: Florian Krohm <fl...@ei...> Date: Thu Mar 6 18:39:26 2025 +0000 s390x: Fix VLRL and VSTRL insns (Bug 498422) The replacement field for these insns is 12-bit wide. So its value cannot possibly be represented by a UChar. Use UShort instead. This was found by disasm-test like so: ./disasm-test --run vlrl *** mismatch VEX: |vlrl %v6,255,4| objdump: |vlrl %v6,4095,4| ./disasm-test --run vstrl *** mismatch VEX: |vstrl %v6,255(%r4),7| objdump: |vstrl %v6,4095(%r4),7| Fixes https://bugs.kde.org/show_bug.cgi?id=498422 Diff: --- NEWS | 1 + VEX/priv/guest_s390_toIR.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index fd470fee78..304ce1c0b7 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 498143 False positive on EVIOCGRAB ioctl 498317 FdBadUse is not a valid CoreError type in a suppression even though it's generated by --gen-suppressions=yes +498422 s390x: Fix VLRL and VSTRL insns 498492 none/tests/amd64/lzcnt64 crashes on FreeBSD compiled with clang 499183 FreeBSD: differences in avx-vmovq output 499212 mmap() with MAP_ALIGNED() returns unaligned pointer diff --git a/VEX/priv/guest_s390_toIR.c b/VEX/priv/guest_s390_toIR.c index 6da5996452..9fddd95495 100644 --- a/VEX/priv/guest_s390_toIR.c +++ b/VEX/priv/guest_s390_toIR.c @@ -4326,7 +4326,7 @@ s390_format_VRRa_VVVMMM(const HChar *(*irgen)(UChar v1, UChar v2, UChar v3, static void s390_format_VSI_URDV(const HChar *(*irgen)(UChar v1, IRTemp op2addr, UChar i3), - UChar v1, UChar b2, UChar d2, UChar i3, UChar rxb) + UChar v1, UChar b2, UShort d2, UChar i3, UChar rxb) { const HChar *mnm; IRTemp op2addr = newTemp(Ity_I64); |
From: Florian K. <fk...@so...> - 2025-03-06 17:43:45
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=b98855efc89a402357469fbde06912a3bc0b0bfd commit b98855efc89a402357469fbde06912a3bc0b0bfd Author: Florian Krohm <fl...@ei...> Date: Thu Mar 6 17:42:05 2025 +0000 s390x: Add disassembly checker (Bug 498037) Add program disasm-test to check that s390_disasm generates the same disassembly for a given insn than objdump -d does. The focus is on insns that have extended mnemonics most of which are vector insns. The checker resides in none/tests/s390x/disasm-test with comprehensive documentation in the README file there. It is integrated into the regression testing framework but currently disabled, because s390_disasm has not been fixed yet. Fixes https://bugs.kde.org/show_bug.cgi?id=498037 Diff: --- .gitignore | 11 + Makefile.am | 1 + NEWS | 1 + configure.ac | 1 + none/tests/s390x/disasm-test/Makefile.am | 35 + none/tests/s390x/disasm-test/README | 210 +++++ .../tests/s390x/disasm-test/disasm-test.stderr.exp | 3 + .../tests/s390x/disasm-test/disasm-test.stdout.exp | 0 none/tests/s390x/disasm-test/disasm-test.vgtest | 6 + none/tests/s390x/disasm-test/filter_stderr | 3 + none/tests/s390x/disasm-test/generate.c | 596 +++++++++++++ none/tests/s390x/disasm-test/main.c | 371 ++++++++ none/tests/s390x/disasm-test/main.h | 101 +++ none/tests/s390x/disasm-test/objdump.c | 237 +++++ none/tests/s390x/disasm-test/objdump.h | 55 ++ none/tests/s390x/disasm-test/opcode.c | 964 +++++++++++++++++++++ none/tests/s390x/disasm-test/verify.c | 149 ++++ none/tests/s390x/disasm-test/vex.c | 145 ++++ none/tests/s390x/disasm-test/vex.h | 32 + 19 files changed, 2921 insertions(+) diff --git a/.gitignore b/.gitignore index de2306df78..c394d27175 100644 --- a/.gitignore +++ b/.gitignore @@ -2231,6 +2231,17 @@ /none/tests/riscv64/integer /none/tests/riscv64/muldiv +# /none/tests/s390x/disasm-test/ +/none/tests/s390x/disasm-test/*.dSYM +/none/tests/s390x/disasm-test/*.stderr.diff* +/none/tests/s390x/disasm-test/*.stderr.out +/none/tests/s390x/disasm-test/*.stdout.diff* +/none/tests/s390x/disasm-test/*.stdout.out +/none/tests/s390x/disasm-test/.deps +/none/tests/s390x/disasm-test/Makefile +/none/tests/s390x/disasm-test/Makefile.in +/none/tests/s390x/disasm-test/disasm-test + # /none/tests/scripts/ /none/tests/scripts/*.dSYM /none/tests/scripts/*.so diff --git a/Makefile.am b/Makefile.am index db8cfa382c..14309dacfa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,7 @@ SUBDIRS = \ perf \ gdbserver_tests \ memcheck/tests/vbit-test \ + none/tests/s390x/disasm-test \ auxprogs \ mpi \ solaris \ diff --git a/NEWS b/NEWS index ad58e72152..fd470fee78 100644 --- a/NEWS +++ b/NEWS @@ -48,6 +48,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 497455 Update drd/scripts/download-and-build-gcc 497723 Enabling Ada demangling breaks callgrind differentiation between overloaded functions and procedures +498037 s390x: Add disassembly checker 498143 False positive on EVIOCGRAB ioctl 498317 FdBadUse is not a valid CoreError type in a suppression even though it's generated by --gen-suppressions=yes diff --git a/configure.ac b/configure.ac index e6ae0501bd..5d3c6d02d4 100755 --- a/configure.ac +++ b/configure.ac @@ -5722,6 +5722,7 @@ AC_CONFIG_FILES([ none/tests/arm/Makefile none/tests/arm64/Makefile none/tests/s390x/Makefile + none/tests/s390x/disasm-test/Makefile none/tests/mips32/Makefile none/tests/mips64/Makefile none/tests/nanomips/Makefile diff --git a/none/tests/s390x/disasm-test/Makefile.am b/none/tests/s390x/disasm-test/Makefile.am new file mode 100644 index 0000000000..7758489219 --- /dev/null +++ b/none/tests/s390x/disasm-test/Makefile.am @@ -0,0 +1,35 @@ +include $(top_srcdir)/Makefile.all.am + +EXTRA_DIST = disasm-test.vgtest disasm-test.stderr.exp disasm-test.stdout.exp + +dist_noinst_SCRIPTS = filter_stderr + +#---------------------------------------------------------------------------- +# Headers +#---------------------------------------------------------------------------- + +pkginclude_HEADERS = +noinst_HEADERS = main.h objdump.h vex.h + +#---------------------------------------------------------------------------- +# disasm_test +#---------------------------------------------------------------------------- + +noinst_PROGRAMS = disasm-test + +SOURCES = \ + main.c \ + generate.c \ + objdump.c \ + opcode.c \ + verify.c \ + vex.c + +disasm_test_SOURCES = $(SOURCES) +disasm_test_CPPFLAGS = $(AM_CPPFLAGS_PRI) \ + -I$(top_srcdir)/VEX/pub \ + -I$(top_srcdir)/VEX/priv +disasm_test_CFLAGS = $(AM_CFLAGS_PRI) +disasm_test_DEPENDENCIES = +disasm_test_LDADD = $(top_builddir)/VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a +disasm_test_LDFLAGS = $(AM_CFLAGS_PRI) @LIB_UBSAN@ diff --git a/none/tests/s390x/disasm-test/README b/none/tests/s390x/disasm-test/README new file mode 100644 index 0000000000..54df05cf98 --- /dev/null +++ b/none/tests/s390x/disasm-test/README @@ -0,0 +1,210 @@ +disasm-test + +The purpose of this program is to ensure that the disassembly as +generated by s390_disasm matches what objdump -d produces for any +given insn. As such the program runs as part of "make regtest". + + +How it works +------------ +1) Given an opcode, generate a C file with testcases. +2) Compile the C file. +3) Run objdump -d on the object file and capture the result in a file. + This file will be referred to as "the objdump file". +4) Read the objdump file, extract the insn bytes and disassembly. +5) Feed the so-extracted insn bytes into VEX's decode-and-irgen + machinery with disassembly (= tracing frontend) being enabled. +6) Intercept the so-disassembled text and compare it with the + disassembly in the objdump file. + + +Invocation +---------- +See disasm-test --help for the most up-to-date instructions. + +disasm-test --all + For all opcodes known to disasm-test, generate testcases and + verify the disassembly. This is how disasm-test is invoked + during regression testing. + +disasm-test --generate OPCODE_NAMEs + For each specified opcode, generate a C file with testcases, + compile it and create the objdump file. + Useful when adding new opcodes. + +disasm-test --verify OBJDUMP_FILEs + For each specified objdump file, verify that the disassembly via VEX + matches. Useful when adding new opcodes. + +disasm-test --run OPCODE_NAMEs + Combines --generate and --verify. Useful when adding new opcodes. + + +Other non-debugging options +--------------------------- +--verbose + Reports activity and miscellaneous information deemed interesting. + +--summary + Write out test generation summary. This option is only observed in + combination with --all. + +--gcc=/path/to/gcc + Specify which GCC to use. Default is: gcc on $PATH. + +--gcc-flags=FLAGS + Specify which flags GCC to use. Default is: "-c -march=arch14". + +--objdump=/path/to/objdump + Specify which objdump to use. Default is: objdump on $PATH. + +--keep-temp + Keep generated files: .c file with testcases, object file, objdump + file, and .vex file + +--show-exc-spec + Show generated insns that cause specification exceptions. + Because insns causing specification exceptions are typically accepted + by GCC and objdump an objdump file may contain them. But comparing + them is pointless. + +--no-show-miscompares + Do not show miscomparing insns. + + +Debugging options +----------------- +--debug + Additional debugging output. + +--d12=INT + Use INT as the value for d12 fields. The given value is checked + for feasibility. + +--d20=INT + Use INT as the value for d20 fields. The given value is checked + for feasibility. + +--sint=INT + Use INT as the only value for signed integer fields. The given value + is NOT checked for feasibility (as the field width is not known). + The value is expected to fit in 32 bits (and is complained about + if it doesn't), as there are no opcodes with immediate operands + that have more than 32 bits. + +--uint=INT + Use INT as the only value for unsigned integer fields. The given value + is NOT checked for feasibility (as the field width is not known). + The value is expected to fit in 32 bits (and is complained about + if it doesn't), as there are no opcodes with immediate operands + that have more than 32 bits. + + +Testcase generation +------------------- +Testcase generation is not exhaustive. That would produce too large a +number of testcases. For example, testing CRB R1,R2,M3,D4(B4) +exhaustively would produce 16x16x16x12x16 = 786432 testcases. Instead, +we attempt to create "interesting" testcases. Like so: + +- for a VR operand pick a VR at random +- for a GPR operand that is not an index or base register pick a GPR + at random +- for a GPR that is base or index register, pick r0 and another GPR + at random +- for a 12-bit displacement pick 0, 1, 2, 4095 +- for a 20-bit displacement pick -524288, -2, -1, 0, 1, 2, 524287 +- for a signed integer field pick the boundary values of its domain and + -2,-1,0,1,2 +- for an unsigned integer field pick the boundary values of its domain + and 1, 2 +- for a mask field, pick all allowed values + +Why are we picking these values? Boundary cases are *always* +interesting, as is 0. '1' is picked because it is odd and '2' is picked +because it is even. + +Note: if an opcode has more than one GPR operand choose different +registers. We do this because we want to catch bugs due to mixed up +registers. +E.g. If the testcase is "brxh r1,r2,8" and s390_disasm produces +"brxh r2,r1,8" we want to catch that. Obviously, to do so the registers +need to be different. The same applies to VRs. + + +Adding a new opcode +------------------- +See extensive documentation at the top of file opcode.c +Any opcode can be added. It is not necessary for the opcode to have +extended mnemonics. + + +Integration into regression testing +----------------------------------- +1) Observe the exit code + + disasm-test --all --no-show-miscompares + + There will be no output to stdout and stderr. If there are no + miscompares in the disassembly the exit code will be 0. Otherwise, + it will be 1. + +2) Observe stderr + + disasm-test --all + + Miscomparing disassembly will be written to stderr. Exit code as + described above. + +3) Observe testcase summary + + disasm-test --all --no-show-miscompares --summary + + Will write information about #testcases as well as failing ones + to stdout. Exit code as described above. + + +Status +------ +Only opcodes with extended mnemonics as identified in Appendix J of the +Principles of Operation are considered. + +There is only partial support for opcodes with optional operands. +In the sense that the generated testcases will always include the +optional operand. + + +TODO +---- +(1) Testcase generation for the "Rotate and ..." family of opcodes needs + to be improved. Several interesting cases involving the T- and Z-bit + are not considered. + +(2) Due to bugs and missing functionality the following miscompares are + observed at this point: + - all vector opcodes (missing functionality) + - c[l][g]rt (bug in s390_disasm) + - bc (bug in objdump 2.38) + +(3) Generated testcases may cause specification exceptions. This + happens iff a constraint involves more than one opcode field. + E.g.: for the VREP opcode the M4 value determines which I2 values + are allowed. This constraint cannot be expressed. However, the + disassembly for such insns is not compared. Use --show-spec-exc + to show those insns. + +(4) In s390_decode_and_irgen the code peeks past the current insn: + + /* If next instruction is execute, stop here */ + if (dis_res->whatNext == Dis_Continue && + (bytes[insn_length] == 0x44 || + (bytes[insn_length] == 0xc6 && (bytes[insn_length + 1] & 0xf) == 0))) { + + Because of this we need to make our insn buffer 7 bytes instead + of 6 and set insn_buf[6] = 0x0. This works because 0x0 != 0x44 + and 0x0 != 0xc6. + Perhaps disable the peek-ahead when inside disasm-test by means + of some global variable? Not pretty either, but explicit. + +(5) For D20XB and D12XB operands add a test with B == X and B != 0 + Not exactly easy to do. diff --git a/none/tests/s390x/disasm-test/disasm-test.stderr.exp b/none/tests/s390x/disasm-test/disasm-test.stderr.exp new file mode 100644 index 0000000000..e6a4c48218 --- /dev/null +++ b/none/tests/s390x/disasm-test/disasm-test.stderr.exp @@ -0,0 +1,3 @@ + +One of --verify, --generate, --run, --all, or --unit-test is required + diff --git a/none/tests/s390x/disasm-test/disasm-test.stdout.exp b/none/tests/s390x/disasm-test/disasm-test.stdout.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/none/tests/s390x/disasm-test/disasm-test.vgtest b/none/tests/s390x/disasm-test/disasm-test.vgtest new file mode 100644 index 0000000000..d7a1a409c1 --- /dev/null +++ b/none/tests/s390x/disasm-test/disasm-test.vgtest @@ -0,0 +1,6 @@ +prog: disasm-test +# args: --all # enable this eventually +# +# NOTE: there are extra newlines in the output which are *not* +# present when disasm-test is invoked by hand. +# Not sure where they are coming from. diff --git a/none/tests/s390x/disasm-test/filter_stderr b/none/tests/s390x/disasm-test/filter_stderr new file mode 100755 index 0000000000..f4c67057ee --- /dev/null +++ b/none/tests/s390x/disasm-test/filter_stderr @@ -0,0 +1,3 @@ +#!/bin/sh + +../../filter_stderr "$@" diff --git a/none/tests/s390x/disasm-test/generate.c b/none/tests/s390x/disasm-test/generate.c new file mode 100644 index 0000000000..7e69085e38 --- /dev/null +++ b/none/tests/s390x/disasm-test/generate.c @@ -0,0 +1,596 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stdio.h> // fprintf +#include <stdlib.h> // system +#include <string.h> // strlen +#include <stdarg.h> // va_list +#include <ctype.h> // isdigit +#include <assert.h> // assert +#include "main.h" // error +#include "objdump.h" // MARK + +// FIXME: if more than one VR or GPR (non-base, non-index) are used in +// an opcode use different register! So we can recognise a mixup in +// register order. E.g. vctz %v2,%v2,3 will not allow to detect whether +// the two registers was mixed up. +static unsigned num_tests; // # generated tests + +static void run_cmd(const char *, ...); + + +static const char * +gpr_operand(unsigned regno) +{ + static const char *gprs[] = { + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + }; + + return gprs[regno]; +} + + +static const char * +vr_operand(unsigned regno) +{ + static const char *vrs[] = { + "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7", + "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", + "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23", + "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31" + }; + + return vrs[regno]; +} + + +static unsigned +random_gpr(int allow_r0) +{ + unsigned regno; + + if (allow_r0) { + regno = rand() % 16; + } else { + do { + regno = rand() % 16; + } while (regno == 0); + } + + return regno; +} + + +static unsigned +random_vr(void) +{ + return rand() % 32; +} + + +#if 0 +/* These functions are currently unused. But may become useful in + alternate test generation strategies that use random values instead + of hardwired interesting ones. */ + +static unsigned +random_uint(unsigned num_bits) +{ + assert(num_bits <= 32); + + long long val = rand(); + return val % (1LL << num_bits); +} + + +static int +random_sint(unsigned num_bits) +{ + assert(num_bits <= 32); + + static int sign = 1; + + long long val = rand(); // positive value + int value = val % (1LL << (num_bits - 1)); + + /* alternate */ + if (sign == -1) + value = -value; + sign = -sign; + return value; +} + + +static unsigned +d12_value(void) +{ + return d12_val_specified ? d12_val : random_uint(12); +} + + +static int +d20_value(void) +{ + return d20_val_specified ? d20_val : random_sint(20); +} + + +static unsigned +uint_value(unsigned num_bits) +{ + if (num_bits > 32) + fatal("integer operand > 32 bits not supported\n"); + return uint_val_specified ? uint_val : random_uint(num_bits); +} + + +static int +sint_value(unsigned num_bits) +{ + if (num_bits > 32) + fatal("integer operand > 32 bits not supported\n"); + return sint_val_specified ? sint_val : random_sint(num_bits); +} +#endif + +/* MASK is a bitvector. For a GPR rk the k'th bit will be set. The + function returns a register number which has not been used and + adjusts the bitvector. */ +static unsigned +unique_gpr(unsigned regno, unsigned *mask) +{ + assert(regno < 16); + assert(*mask != ~0U); // Paranoia: avoid infinite loop + + unsigned bit = 1 << regno; + while (*mask & bit) { + regno = random_gpr(/* allow_r0 */1); + bit = 1 << regno; + } + *mask |= bit; + return regno; +} + + +/* Like unique_gpr */ +static unsigned +unique_vr(unsigned regno, unsigned *mask) +{ + assert(regno < 32); + assert(*mask != ~0U); // Paranoia: avoid infinite loop + + unsigned bit = 1 << regno; + while (*mask & bit) { + regno = random_vr(); + bit = 1 << regno; + } + *mask |= bit; + return regno; +} + + +/* Field */ +typedef struct { + const opnd *operand; // the operand to which this field belongs + int is_displacement; // only relevant for OPND_D12/20[X]B operands + int is_length; // only relevant for OPND_D12LB operands + int is_vr; // only relevant for OPND_D12VB operands + long long assigned_value; +} field; + + +/* Write out a single ASM statement for OPC. */ +static void +write_asm_stmt(FILE *fp, const opcode *opc, const field fields[]) +{ + fprintf(fp, " asm volatile(\"%s ", opc->name); + + unsigned gpr_mask, vr_mask, regno; + int inc; + int needs_comma = 0; + + gpr_mask = vr_mask = 0; + for (int i = 0; i < opc->num_fields; i += inc) { + const opnd *operand = fields[i].operand; + + inc = 1; // for most operand kinds + + if (needs_comma++) + fputc(',', fp); + switch (operand->kind) { + case OPND_GPR: + regno = unique_gpr(fields[i].assigned_value, &gpr_mask); + fprintf(fp, "%s", gpr_operand(regno)); + break; + case OPND_VR: + regno = unique_vr(fields[i].assigned_value, &vr_mask); + fprintf(fp, "%s", vr_operand(regno)); + break; + case OPND_D12XB: + case OPND_D20XB: { + long long d = fields[i].assigned_value; + const char *x = gpr_operand(fields[i + 1].assigned_value); + const char *b = gpr_operand(fields[i + 2].assigned_value); + fprintf(fp, "%lld(%s,%s)", d, x, b); + inc = 3; + break; + } + case OPND_D12VB: { + long long d = fields[i].assigned_value; + const char *v = vr_operand(fields[i + 1].assigned_value); + const char *b = gpr_operand(fields[i + 2].assigned_value); + fprintf(fp, "%lld(%s,%s)", d, v, b); + inc = 3; + break; + } + case OPND_D12LB: { + long long d = fields[i].assigned_value; + unsigned l = fields[i + 1].assigned_value; + const char *b = gpr_operand(fields[i + 2].assigned_value); + fprintf(fp, "%lld(%u,%s)", d, l + 1, b); + inc = 3; + break; + } + case OPND_D12B: + case OPND_D20B: { + long long d = fields[i].assigned_value; + const char *b = gpr_operand(fields[i + 1].assigned_value); + fprintf(fp, "%lld(%s)", d, b); + inc = 2; + break; + } + case OPND_MASK: + case OPND_SINT: + case OPND_UINT: + fprintf(fp, "%lld", fields[i].assigned_value); + break; + case OPND_PCREL: + fprintf(fp, "%lld*2", fields[i].assigned_value); + break; + default: + assert(0); + } + } + fprintf(fp, "\");\n"); + + ++num_tests; +} + + +/* IX identifies the element of the FIELDS array to which a value + will be assigned in this iteration. */ +static void +iterate(FILE *fp, const opcode *opc, field fields[], unsigned ix) +{ + /* All fields are assigned. Write out the asm stmt */ + if (ix == opc->num_fields) { + write_asm_stmt(fp, opc, fields); + return; + } + + field *f = fields + ix; + const opnd *operand = f->operand; + + switch (operand->kind) { + case OPND_GPR: + if (operand->name[0] == 'b' || operand->name[0] == 'x') { + /* Choose r0 */ + f->assigned_value = 0; + iterate(fp, opc, fields, ix + 1); + /* Choose any GPR other than r0 */ + f->assigned_value = random_gpr(/* r0_allowed */ 0); + iterate(fp, opc, fields, ix + 1); + } else { + /* Choose any GPR */ + f->assigned_value = random_gpr(/* r0_allowed */ 1); + iterate(fp, opc, fields, ix + 1); + } + break; + + case OPND_VR: + f->assigned_value = random_vr(); // Choose any VR + iterate(fp, opc, fields, ix + 1); + break; + + case OPND_D12B: + case OPND_D12XB: + case OPND_D12LB: + case OPND_D12VB: + if (f->is_displacement) { + if (d12_val_specified) { + f->assigned_value = d12_val; + iterate(fp, opc, fields, ix + 1); + } else { + /* Choose these interesting values */ + static const long long values[] = { 0, 1, 2, 0xfff }; + + for (int i = 0; i < sizeof values / sizeof *values; ++i) { + f->assigned_value = values[i]; + iterate(fp, opc, fields, ix + 1); + } + } + } else if (f->is_length) { + /* Choose these interesting values */ + static const long long values[] = { 0, 1, 2, 255 }; + + for (int i = 0; i < sizeof values / sizeof *values; ++i) { + f->assigned_value = values[i]; + iterate(fp, opc, fields, ix + 1); + } + } else if (f->is_vr) { + /* v0 is not special AFAICT */ + f->assigned_value = random_vr(); + iterate(fp, opc, fields, ix + 1); + } else { + /* Base or index register */ + f->assigned_value = 0; + iterate(fp, opc, fields, ix + 1); + f->assigned_value = random_gpr(/* r0_allowed */ 0); + iterate(fp, opc, fields, ix + 1); + } + break; + + case OPND_D20B: + case OPND_D20XB: + if (f->is_displacement) { + if (d20_val_specified) { + f->assigned_value = d20_val; + iterate(fp, opc, fields, ix + 1); + } else { + /* Choose these interesting values */ + static const long long values[] = { + 0, 1, 2, -1, -2, 0x7ffff, -0x80000 + }; + + for (int i = 0; i < sizeof values / sizeof *values; ++i) { + f->assigned_value = values[i]; + iterate(fp, opc, fields, ix + 1); + } + } + } else { + /* base or index register */ + f->assigned_value = 0; + iterate(fp, opc, fields, ix + 1); + f->assigned_value = random_gpr(/* r0_allowed */ 0); + iterate(fp, opc, fields, ix + 1); + } + break; + + case OPND_SINT: + case OPND_PCREL: + if (sint_val_specified) { + f->assigned_value = sint_val; + iterate(fp, opc, fields, ix + 1); + } else { + if (operand->allowed_values == NULL) { + /* No constraint: Choose these interesting values */ + const long long values[] = { + 0, 1, 2, -1, -2, (1LL << (operand->num_bits - 1)) - 1, + -(1LL << (operand->num_bits - 1)) + }; + + for (int i = 0; i < sizeof values / sizeof *values; ++i) { + f->assigned_value = values[i]; + iterate(fp, opc, fields, ix + 1); + } + } else { + /* Constraint. Choose only allowed values */ + unsigned num_val = operand->allowed_values[0]; + for (int i = 1; i <= num_val; ++i) { + f->assigned_value = operand->allowed_values[i]; + iterate(fp, opc, fields, ix + 1); + } + } + } + break; + + case OPND_UINT: + if (uint_val_specified) { + f->assigned_value = uint_val; + iterate(fp, opc, fields, ix + 1); + } else { + if (operand->allowed_values == NULL) { + /* No constraint: Choose these interesting values */ + const long long values[] = { + 0, 1, 2, (1LL << operand->num_bits) - 1 + }; + + for (int i = 0; i < sizeof values / sizeof *values; ++i) { + f->assigned_value = values[i]; + iterate(fp, opc, fields, ix + 1); + } + } else { + /* Constraint. Choose only allowed values */ + unsigned num_val = operand->allowed_values[0]; + for (int i = 1; i <= num_val; ++i) { + f->assigned_value = operand->allowed_values[i]; + iterate(fp, opc, fields, ix + 1); + } + } + } + break; + + case OPND_MASK: + if (operand->allowed_values == NULL) { + /* No constraint. Choose all possible values */ + unsigned maxval = (1u << operand->num_bits) - 1; + for (int val = 0; val <= maxval; ++val) { + f->assigned_value = val; + iterate(fp, opc, fields, ix + 1); + } + } else { + /* Constraint. Choose only allowed values */ + unsigned num_val = operand->allowed_values[0]; + for (int i = 1; i <= num_val; ++i) { + f->assigned_value = operand->allowed_values[i]; + iterate(fp, opc, fields, ix + 1); + } + } + break; + + case OPND_INVALID: + default: + assert(0); + } +} + + +static void +generate(FILE *fp, const opcode *opc) +{ + /* Array of opcode fields to which we need to assign values. */ + field fields[opc->num_fields]; + field *f; + + int ix = 0; + for (int i = 0; i < opc->num_opnds; ++i) { + const opnd *operand = opc->opnds + i; + + switch (operand->kind) { + case OPND_GPR: + case OPND_VR: + case OPND_SINT: + case OPND_UINT: + case OPND_PCREL: + case OPND_MASK: + f = fields + ix++; + f->operand = operand; + break; + + case OPND_D12XB: + case OPND_D20XB: + for (int j = 1; j <= 3; ++j) { + f = fields + ix++; + f->operand = operand; + f->is_displacement = j == 1; + f->is_length = 0; + f->is_vr = 0; + } + break; + + case OPND_D12B: + case OPND_D20B: + for (int j = 1; j <= 2; ++j) { + f = fields + ix++; + f->operand = operand; + f->is_displacement = j == 1; + f->is_length = 0; + f->is_vr = 0; + } + break; + + case OPND_D12LB: + for (int j = 1; j <= 3; ++j) { + f = fields + ix++; + f->operand = operand; + f->is_displacement = j == 1; + f->is_length = j == 2; + f->is_vr = 0; + } + break; + + case OPND_D12VB: + for (int j = 1; j <= 3; ++j) { + f = fields + ix++; + f->operand = operand; + f->is_displacement = j == 1; + f->is_length = 0; + f->is_vr = j == 2; + } + break; + + case OPND_INVALID: + default: + assert(0); + } + } + assert(ix == opc->num_fields); + + iterate(fp, opc, fields, 0); +} + + +unsigned +generate_tests(const opcode *opc) +{ + srand(42); + + if (verbose) + printf("...generating testcases for '%s'\n", opc->name); + + num_tests = 0; + + char file[strlen(opc->name) + 3]; + sprintf(file, "%s.c", opc->name); + + FILE *fp = fopen(file, "w"); + if (fp == NULL) { + error("%s: fopen failed\n", file); + return 0; + } + + fprintf(fp, "void\n"); + fprintf(fp, "main(void)\n"); + fprintf(fp, "{\n"); + fprintf(fp, " asm volatile(\"%s\");\n", MARK); + generate(fp, opc); + fprintf(fp, " asm volatile(\"%s\");\n", MARK); + fprintf(fp, "}\n"); + fclose(fp); + + if (verbose) + printf("...%u testcases generated for '%s'\n", num_tests, + opc->name); + + run_cmd("%s %s %s.c", gcc, gcc_flags, opc->name); + run_cmd("%s --disassemble=%s %s.o > %s.dump", objdump, FUNCTION, + opc->name, opc->name); + + return num_tests; +} + + +static void +run_cmd(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + int need = vsnprintf((char []){ 0 }, 1, fmt, args); + va_end(args); + + char cmd[need + 1]; + va_list args2; + va_start(args2, fmt); + vsnprintf(cmd, sizeof cmd, fmt, args2); + va_end(args2); + + if (debug) + printf("Running command: %s\n", cmd); + + int rc = system(cmd); + + if (rc != 0) + error("Command '%s' failed\n", cmd); +} diff --git a/none/tests/s390x/disasm-test/main.c b/none/tests/s390x/disasm-test/main.c new file mode 100644 index 0000000000..75d007b933 --- /dev/null +++ b/none/tests/s390x/disasm-test/main.c @@ -0,0 +1,371 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stddef.h> // NULL +#include <stdlib.h> // exit, malloc +#include <stdio.h> // vfprintf +#include <stdarg.h> // va_list +#include <string.h> // strchr +#include <assert.h> // assert +#include <unistd.h> // unlink +#include "vex.h" // vex_init +#include "main.h" + +int verbose, debug, show_spec_exc, show_miscompares; +int d12_val, d20_val; +long long uint_val, sint_val; +int d12_val_specified, d20_val_specified; +int uint_val_specified, sint_val_specified; + +const char *gcc = "gcc"; // path to GCC +const char *objdump = "objdump"; // path to objdump +const char *gcc_flags = "-c -march=arch14"; + +#define CHECK_CLO(x, s) (strncmp(x, s, sizeof s - 1) == 0) + +static const char usage[] = + "Usage:\n\n" + "disasm-test --generate OPCODES\n" + " Generate testcases for the given opcodes and prepare objdump files.\n\n" + "disasm-test --verify FILES\n" + " Read specified objdump files and compare with VEX disassembly.\n\n" + "disasm-test --run OPCODES\n" + " Generate testcases for the given opcodes and compare the disassembly.\n\n" + "disasm-test --all\n" + " For all opcodes generate testcases and compare the disassembly.\n\n" + "disasm-test --unit-test\n" + " Run unit tests. All other command line options are ignored.\n\n" + "Additional options:\n" + " --verbose\n" + " --debug\n" + " --gcc=/path/to/gcc\n" + " --gcc-flags=FLAGS\n" + " --objdump=/path/to/objdump\n" + " --d12=INT - Use INT as value for d12 offsets\n" + " --d20=INT - Use INT as value for d20 offsets\n" + " --sint=INT - Use INT as value for signed integer fields\n" + " --uint=INT - Use INT as value for unsigned integer fields\n" + " --keep-temp - Do not remove temporary files\n" + " --summary - Output test generation summary (with --all)\n" + " --unit-test - Run unit tests\n" + " --show-spec-exc - Show insns causing specification exceptions\n" + " --no-show-miscompares - Do not show disassembly miscompares\n" + ; + +static long long get_clo_value(const char *, const char *, long long, + long long); +static void remove_temp_files(const char *); +static int opcode_has_errors(const opcode *); + +static int keep_temp = 0; +static int summary = 0; + + +/* Return code: 0 no disassembly mismatches + Return code: 1 at least one disassembly mismatch + + Specification exceptions do not influence the return code. */ +int +main(int argc, char *argv[]) +{ + int all = 0, verify = 0, generate = 0, unit_test = 0; + int num_clargs = 0; + int run = 0; + const char *clargs[argc]; + + assert(sizeof(long long) == 8); + + /* Change to line buffering */ + setlinebuf(stdout); + setlinebuf(stderr); + + show_miscompares = 1; + + /* Collect options and arguments */ + for (int i = 1; i < argc; ++i) { + const char *clo = argv[i]; + + if (CHECK_CLO(clo, "--verify")) { + verify = 1; + } else if (CHECK_CLO(clo, "--generate")) { + generate = 1; + } else if (CHECK_CLO(clo, "--all")) { + all = 1; + } else if (CHECK_CLO(clo, "--verbose")) { + verbose = 1; + } else if (CHECK_CLO(clo, "--debug")) { + debug = 1; + } else if (CHECK_CLO(clo, "--summary")) { + summary = 1; + } else if (CHECK_CLO(clo, "--unit-test")) { + unit_test = 1; + } else if (CHECK_CLO(clo, "--show-spec-exc")) { + show_spec_exc = 1; + } else if (CHECK_CLO(clo, "--no-show-miscompares")) { + show_miscompares = 0; + } else if (CHECK_CLO(clo, "--keep-temp")) { + keep_temp = 1; + } else if (CHECK_CLO(clo, "--run")) { + run = 1; + } else if (CHECK_CLO(clo, "--help")) { + printf("%s\n", usage); + return 0; + } else if (CHECK_CLO(clo, "--gcc=")) { + gcc = strchr(clo, '=') + 1; + } else if (CHECK_CLO(clo, "--gcc-flags=")) { + gcc_flags = strchr(clo, '=') + 1; + } else if (CHECK_CLO(clo, "--objdump=")) { + objdump = strchr(clo, '=') + 1; + } else if (CHECK_CLO(clo, "--d12=")) { + d12_val = get_clo_value(clo, "d12", 0, 0xfff); + } else if (CHECK_CLO(clo, "--d20=")) { + d20_val = get_clo_value(clo, "d20", -0x80000, 0x7ffff); + } else if (CHECK_CLO(clo, "--sint=")) { + /* Integer field is restricted to 32-bit */ + long long max = 0x7fffffff; + sint_val = get_clo_value(clo, "sint", -max - 1, max); + } else if (CHECK_CLO(clo, "--uint=")) { + /* Integer field is restricted to 32-bit */ + uint_val = get_clo_value(clo, "uint", 0, 0xffffffffU); + } else { + if (strncmp(clo, "--", 2) == 0) + fatal("Invalid command line option '%s'\n", clo); + clargs[num_clargs++] = clo; + } + } + + /* Check consistency of command line options */ + if (verify + generate + run + all + unit_test == 0) + fatal("One of --verify, --generate, --run, --all, or --unit-test " + "is required\n"); + if (verify + generate + run + all + unit_test != 1) + fatal("At most one of --verify, --generate, --run, --all, or " + " --unit-test can be given\n"); + + vex_init(); + + if (generate) { + if (num_clargs == 0) + fatal("Missing opcode name[s]\n"); + + for (int i = 0; i < num_clargs; ++i) { + const char *name = clargs[i]; + + opcode *opc = get_opcode_by_name(name); + + if (opc == NULL) { + error("'%s' is not a recognised opcode\n", name); + } else if (opcode_has_errors(opc)) { + error("Opcode '%s' ignored due to syntax errors\n", name); + } else { + generate_tests(opc); + release_opcode(opc); + } + } + return 0; + } + + if (verify) { + if (num_clargs == 0) + fatal("Missing file name[s]\n"); + + int num_mismatch = 0; + + for (int i = 0; i < num_clargs; ++i) { + verify_stats stats = verify_disassembly(clargs[i]); + num_mismatch += stats.num_mismatch; + } + return num_mismatch != 0; + } + + if (run) { + if (num_clargs == 0) + fatal("Missing opcode name[s]\n"); + + unsigned num_mismatch = 0; + + for (int i = 0; i < num_clargs; ++i) { + const char *name = clargs[i]; + + opcode *opc = get_opcode_by_name(name); + + if (opc == NULL) { + error("'%s' is not a recognised opcode\n", name); + } else if (opcode_has_errors(opc)) { + error("Opcode '%s' ignored due to syntax errors\n", name); + } else { + generate_tests(opc); + + char file[strlen(name) + 10]; // large enough + sprintf(file, "%s.dump", name); + + verify_stats stats = verify_disassembly(file); + num_mismatch += stats.num_mismatch; + + if (! keep_temp) + remove_temp_files(name); + release_opcode(opc); + } + } + return num_mismatch != 0; + } + + if (all) { + if (num_clargs != 0) + fatal("Excess arguments on command line\n"); + + unsigned num_tests, num_verified, num_mismatch, num_spec_exc; + num_tests = num_verified = num_mismatch = num_spec_exc = 0; + + for (int i = 0; i < num_opcodes; ++i) { + opcode *opc = get_opcode_by_index(i); // never NULL + + if (opcode_has_errors(opc)) { + error("Opcode '%s' ignored due to syntax errors\n", + opc->name); + continue; + } + num_tests += generate_tests(opc); + + char file[strlen(opc->name) + 10]; + sprintf(file, "%s.dump", opc->name); + + verify_stats stats = verify_disassembly(file); + + num_verified += stats.num_verified; + num_mismatch += stats.num_mismatch; + num_spec_exc += stats.num_spec_exc; + + if (! keep_temp) + remove_temp_files(opc->name); + release_opcode(opc); + } + if (verbose || summary) { + printf("Total: %6u tests generated\n", num_tests); + printf("Total: %6u insns verified\n", num_verified); + printf("Total: %6u disassembly mismatches\n", num_mismatch); + printf("Total: %6u specification exceptions\n", num_spec_exc); + } + return num_mismatch != 0; + } + + if (unit_test) + run_unit_tests(); + + return 0; +} + + +static void +remove_temp_files(const char *op) +{ + char file[strlen(op) + 10]; // large enough + static const char *suffix[] = { ".c", ".o", ".dump", ".vex" }; + + for (int i = 0; i < sizeof suffix / sizeof *suffix; ++i) { + sprintf(file, "%s%s", op, suffix[i]); + unlink(file); + } +} + + +/* A few convenience utilities */ +void +error(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + + +void +fatal(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + exit(EXIT_FAILURE); +} + + +void * +mallock(unsigned n) +{ + void *p = malloc(n); + + if (p == NULL) + fatal("malloc failed\n"); + return p; +} + + +char * +strsave(const char *s) +{ + return strcpy(mallock(strlen(s) + 1), s); +} + + +char * +strnsave(const char *s, unsigned len) +{ + char *p = memcpy(mallock(len + 1), s, len); + + p[len] = '\0'; + return p; +} + + +static long long +get_clo_value(const char *clo, const char *field_name, long long min, + long long max) +{ + long long value; + + const char *p = strchr(clo, '=') + 1; // succeeds + + if (sscanf(p, "%lld", &value) != 1) + fatal("%s value '%s' is not an integer\n", field_name, p); + if (value < min || value > max) + fatal("%s value '%lld' is out of range\n", field_name, value); + return value; +} + + +/* Return 1, if the given opcode has at least one invalid operand. + This indicates that there were parse errors earlier. */ +static int +opcode_has_errors(const opcode *opc) +{ + const opnd *opnds = opc->opnds; + + for (int i = 0; i < opc->num_opnds; ++i) { + if (opnds[i].kind == OPND_INVALID) + return 1; + } + return 0; +} diff --git a/none/tests/s390x/disasm-test/main.h b/none/tests/s390x/disasm-test/main.h new file mode 100644 index 0000000000..c988d8874e --- /dev/null +++ b/none/tests/s390x/disasm-test/main.h @@ -0,0 +1,101 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef MAIN_H +#define MAIN_H + +/* The various kinds of operands. */ +typedef enum { + OPND_GPR, + OPND_VR, + OPND_D12LB, + OPND_D12XB, + OPND_D12VB, + OPND_D20XB, + OPND_D12B, + OPND_D20B, + OPND_SINT, + OPND_UINT, + OPND_MASK, + OPND_PCREL, + OPND_INVALID +} opnd_t; + +/* An operand */ +typedef struct { + char *name; + opnd_t kind; + unsigned num_bits; + int is_unsigned; + // NULL = no values specified. Otherwise, values[0] == #values + // and values[1..#values] are the values. + long long *allowed_values; +} opnd; + +/* An opcode */ +typedef struct { + char *name; + opnd *opnds; + unsigned num_opnds; + /* When generating a testcase this is the number of fields we + need to assign a value to */ + unsigned num_fields; +} opcode; + +typedef struct { + unsigned num_verified; + unsigned num_mismatch; + unsigned num_spec_exc; +} verify_stats; + +__attribute__((format(printf, 1, 2))) +void error(const char *, ...); +__attribute__((noreturn)) __attribute__((format(printf, 1, 2))) +void fatal(const char *, ...); + +verify_stats verify_disassembly(const char *); +unsigned generate_tests(const opcode *); +opcode *get_opcode_by_name(const char *); +opcode *get_opcode_by_index(unsigned); +void release_opcode(opcode *); +void run_unit_tests(void); + +void *mallock(unsigned); +char *strsave(const char *); +char *strnsave(const char *, unsigned); + +extern int verbose; +extern int debug; +extern int show_spec_exc; +extern int show_miscompares; +extern int d12_val, d20_val; +extern long long sint_val, uint_val; +extern int d12_val_specified, d20_val_specified; +extern int uint_val_specified, sint_val_specified; +extern unsigned num_opcodes; +extern const char *gcc; +extern const char *gcc_flags; +extern const char *objdump; + +#endif // MAIN_H diff --git a/none/tests/s390x/disasm-test/objdump.c b/none/tests/s390x/disasm-test/objdump.c new file mode 100644 index 0000000000..62d8346540 --- /dev/null +++ b/none/tests/s390x/disasm-test/objdump.c @@ -0,0 +1,237 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stddef.h> // NULL +#include <stdio.h> // sprintf +#include <stdlib.h> // free +#include <string.h> // strchr +#include <ctype.h> // isdigit +#include "main.h" // error +#include "objdump.h" + +static int get_nibble(const char *); +static int get_byte(const char *); + + +objdump_file * +read_objdump(const char *file) +{ + const char *function = FUNCTION; + const char *mark = MARK; + + /* Slurp file into memory */ + FILE *fp = fopen(file, "rb"); + if (fp == NULL) { + error("%s: fopen failed\n", file); + return NULL; + } + + /* Determine file size */ + int rc = fseek(fp, 0, SEEK_END); + if (rc < 0) { + error("%s: fseek failed\n", file); + return NULL; + } + + long size = ftell(fp); + if (size < 0) { + error("%s: ftell failed\n", file); + return NULL; + } + rewind(fp); + + char *const buf = mallock(size + 1); + size_t num_read = fread(buf, 1, size, fp); + if (num_read != size) { + error("%s: fread failed\n", file); + free(buf); + return NULL; + } + buf[size] = '\0'; + + fclose(fp); + + /* Determine the number of lines in the file. This number + exceeds the number of lines containing insns. */ + unsigned num_lines = 0; + + for (char *p = buf; *p; ++p) { + if (*p == '\n') { + *p = '\0'; + ++num_lines; + } + } + + /* Allocate an objdump_file. */ + objdump_file *ofile = mallock(sizeof (objdump_file)); + + ofile->filebuf = buf; + ofile->lines = mallock(num_lines * sizeof(objdump_line)); + + /* Locate the line containing <FUNCTION>: */ + char string[strlen(function) + 3 + 1]; + sprintf(string, "<%s>:", function); + + char *cur, *next = 0; // shut up, GCC + const char *end = buf + num_read; + + for (cur = buf; cur != end; cur = next) { + const char *line = cur; + next = strchr(line, '\0') + 1; + if (strstr(line, string)) + break; + } + + /* Process the lines containing insns. These are the lines between + the 1st and 2nd MARK. */ + unsigned linecnt = 0; + int marker_seen = 0; + for (cur = next; cur != end; cur = next) { + char *line = cur; + + next = strchr(line, '\0') + 1; + + char *p; + for (p = line; isspace(*p); ++p) + ; + + if (*p == '\0') continue; // blank line allowed + + unsigned address = 0; + while (*p != ':') { + address = (address << 4) + get_nibble(p); + ++p; + } + + ++p; // skip ':' + + while (isspace(*p)) + ++p; + + /* The leftmost two bits (0:1) encode the length of the insn + in bytes: + 00 -> 2 bytes, 01 -> 4 bytes, 10 -> 4 bytes, 11 -> 6 bytes. */ + unsigned char byte = get_byte(p); + unsigned insn_len = ((((byte >> 6) + 1) >> 1) + 1) << 1; + + /* Temporary buffer. */ + char insn_bytes[6] = { 0 }; + + for (int i = 0; i < insn_len; ++i) { + insn_bytes[i] = get_byte(p); + p += 3; + } + + while (isspace(*p)) // skip white space to disassembled text + ++p; + + char *dis_insn = p; + + /* Remove symbolic jump targets, if any. E.g. change + 1b68: c0 e5 ff ff fd a4 brasl %r14,16b0 <puts@plt> to + 1b68: c0 e5 ff ff fd a4 brasl %r14,16b0 + */ + p = strchr(p, '<'); + if (p) { + *p-- = '\0'; + while (isspace(*p)) // remove trailing white space + *p-- = '\0'; + } + + if (strncmp(dis_insn, mark, strlen(mark)) == 0) { + if (marker_seen) + break; // we're done + marker_seen = 1; + } else { + if (marker_seen == 1) { + /* Add the line */ + objdump_line *oline = ofile->lines + linecnt++; + oline->address = address; + oline->insn_len = insn_len; + oline->disassembled_insn = dis_insn; + memcpy(oline->insn_bytes, insn_bytes, sizeof insn_bytes); + + /* Extra byte to allow the decoder to peek past the end of + the current insn */ + // FIXME: introduce global variable that is observed in + // FIXME: the decoder which disables peeking ahead ? + oline->insn_bytes[insn_len] = 0x00; + } + } + } + + if (marker_seen == 0) { + error("%s is not a valid objdump -d file\n", file); + release_objdump(ofile); + return NULL; + } + + ofile->num_lines = linecnt; + + return ofile; +} + + +/* Free all memory allocated for the objdump file */ +void +release_objdump(objdump_file *ofile) +{ + free(ofile->filebuf); + free(ofile->lines); + free(ofile); +} + + +static int +get_nibble(const char *p) +{ + int c = *p; + + if (isdigit(c)) + return c - '0'; + + switch (tolower(c)) { + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + default: + break; + } + + error("%s: get_nibble failed; continuing with fingers crossed\n", p); + return 0; +} + + +static int +get_byte(const char *p) +{ + int n1 = get_nibble(p); + int n2 = get_nibble(p + 1); + + return (n1 << 4) + n2; +} diff --git a/none/tests/s390x/disasm-test/objdump.h b/none/tests/s390x/disasm-test/objdump.h new file mode 100644 index 0000000000..388943f7a7 --- /dev/null +++ b/none/tests/s390x/disasm-test/objdump.h @@ -0,0 +1,55 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef OBJDUMP_H +#define OBJDUMP_H + +/* An opcode which marks the begin and end of a sequence of insns + in a testcase whose disassembly should be verified. */ +#define MARK "csch" + +/* Name of the C function containing the generated insns. */ +#define FUNCTION "main" + +/* INSN_BYTES needs an extra byte because s390_decode_and_irgen peeks + at the next instruction to handle some special case. And in case + of INSN_BYTES having only 6 elements that would be an out-of-bounds + memory access. insn_bytes[insn_len] will always be 0x00. */ +typedef struct { + unsigned address; + unsigned insn_len; + unsigned char insn_bytes[6 + 1]; + const char *disassembled_insn; // points into objdump_file::filebuf +} objdump_line; + +typedef struct { + char *filebuf; // contents of objdump file; will be modified ! + unsigned num_lines; // #lines containing insns + objdump_line *lines; +} objdump_file; + +objdump_file *read_objdump(const char *); +void release_objdump(objdump_file *); + +#endif // OBJDUMP_H diff --git a/none/tests/s390x/disasm-test/opcode.c b/none/tests/s390x/disasm-test/opcode.c new file mode 100644 index 0000000000..daa4899087 --- /dev/null +++ b/none/tests/s390x/disasm-test/opcode.c @@ -0,0 +1,964 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2024-2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stdio.h> // printf +#include <string.h> // strlen +#include <stdlib.h> // free +#include <assert.h> // assert +#include <ctype.h> // isdigit +#include "main.h" // error + +/* Each line in the initialiser is an opcode specification which + consists of two parts: opcode name and opcode operands. + Name and operands are separated by white space. Operands are + separated by ','. + + Operands should not be confused with fields. E.g. the "bc" + opcode has 2 operands (m1 and d12(x2,b2)) but 4 fields (m,d,x,b). + + The following naming conventions are observed: + + - 'r[0-9]+' denotes a GPR (4-bit wide unsigned value) + - 'b[0-9]+' denotes a GPR used as base register + - 'x[0-9]+' denotes a GPR used as index register + - 'v[0-9]+' denotes a VR (5-bit wide unsigned value) + - 'm[0-9]+' denotes a 4-bit mask (an unsigned value) + - 'l' denotes an 8-bit length (an unsigned value) + - 'l[0-9]+' denotes an 8-bit length (an unsigned value) + - 'i[0-9]+' denotes an integer + You must specify #bits and signedness like so: + i2:8u meaning: 8-bit wide, unsigned integer contents + i3:12s meaning: 12-bit wide, signed integer contents + - 'ri[0-9]+' denotes an integer that is used for PC-relative + addressing. You must specify #bits and signedness. + - 'd12' denotes a 12-bit wide displacement (an unsigned integer) + - 'd20' denotes a 20-bit wide displacement (a signed integer) + + It is also possible to restrict the values that may be assigned to an + operand (typically a mask). This is heavily used by vector opcodes. + + Example: + m4:{ 0..4 } values 0,1,2,3,4 are allowed + m4:{ 0,1,2,3,4 } same as above + m5:{ 0,1,3..7 } values 0,1,3,4,5,6,7 are allowed + + If you need to specify #bits, signedness and allowed values you + need to provide those in the order: signedness, #bits, allowed + values. E.g. i2:s8{-10..42} +*/ +static const char *opcodes[] = { + /* Unsorted list of opcodes (other than vector ops) with + extended mnemonics. See also: + Appendix J, Principles of Operation */ + "bic m1,d20(x2,b2)", + "bcr m1,r2", + "bc m1,d12(x2,b2)", + "bras r1,ri2:s16", + "brasl r1,ri2:s32", + "brc m1,ri2:s16", + "brcl m1,ri2:s32", + "brct r1,ri2:s16", + "brctg r1,ri2:s16", + "brcth r1,ri2:s32", + "brxh r1,r3,ri2:s16", + "brxhg r1,r3,ri2:s16", + "brxle r1,r3,ri2:s16", + "brxlg r1,r3,ri2:s16", + "crb r1,r2,m3,d12(b4)", + "cgrb r1,r2,m3,d12(b4)", + "crj r1,r2,m3,ri4:s16", + "cgrj r1,r2,m3,ri4:s16", + "crt r1,r2,m3", + "cgrt r1,r2,m3", + "cib r1,i2:s8,m3,d12(b4)", + "cgib r1,i2:s8,m3,d12(b4)", + "cij r1,i2:s8,m3,ri4:s16", + "cgij r1,i2:s8,m3,ri4:s16", + "cit r1,i2:s16,m3", + "cgit r1,i2:s16,m3", + "clrb r1,r2,m3,d12(b4)", + "clgrb r1,r2,m3,d12(b4)", + "clrj r1,r2,m3,ri4:s16", + "clgrj r1,r2,m3,ri4:s16", + "clrt r1,r2,m3", + "clgrt r1,r2,m3", + "clt r1,m3,d20(b2)", + "clgt r1,m3,d20(b2)", + "clib r1,i2:u8,m3,d12(b4)", + "clgib r1,i2:u8,m3,d12(b4)", + "clij r1,i2:u8,m3,ri4:s16", + "clgij r1,i2:u8,m3,ri4:s16", + "clfit r1,i2:u16,m3", + "clgit r1,i2:u16,m3", + "iilf r1,i2:u32", + "lochhi r1,i2:s16,m3", + "lochi r1,i2:s16,m3", + "locghi r1,i2:s16,m3", + "locfhr r1,r2,m3", + "locfh r1,d20(b2),m3", + "llilf r1,i2:u32", + "locr r1,r2,m3", + "locgr r1,r2,m3", + "loc r1,d20(b2),m3", + "locg r1,d20(b2),m3", + "nork r1,r2,r3", + "nogrk r1,r2,r3", + "rnsbg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME un/signed i3/4/5 ? t-bit ? z-bit? + "rxsbg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "risbg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "risbgn r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "risbhg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "risblg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "rosbg r1,r2,i3:u8,i4:u8,i5:u8", // FIXME ditto + "selr r1,r2,r3,m4", + "selgr r1,r2,r3,m4", + "selfhr r1,r2,r3,m4", + "stocfh r1,d20(b2),m3", + "stoc r1,d20(b2),m3", + "stocg r1,d20(b2),m3", + + /* Misc. other opcodes */ + "cksm r1,r2", // make sure, it gets disassmbled (BZ 495817) + "clcl r1,r2", // make sure, it gets disassmbled (BZ 495817) + "mvcl r1,r2", // make sure, it gets disassmbled (BZ 495817) + + // If a set of allowed values is specified for an operand this + // implies that any other value would cause a specification exception. + // UNLESS otherwise noted. + + // Chapter 21: Vector Overview and Support Instructions + "vbperm v1,v2,v3", + "vgef v1,d12(v2,b2),m3:{0,1,2,3}", + "vgeg v1,d12(v2,b2),m3:{0,1}", + "vgbm v1,i2:u16", + "vgm v1,i2:u8,i3:u8,m4:{0..3}", + "vl v1,d12(x2,b2),m3:{0,3,4}", // no spec. exc + "vlr v1,v2", + "vlrep v1,d12(x2,b2),m3:{0..3}", + "vlebrh v1,d12(x2,b2),m3:{0..7}", + "vlebrf v1,d12(x2,b2),m3:{0..3}", + "vlebrg v1,d12(x2,b2),m3:{0,1}", + "vlbrrep v1,d12(x2,b2),m3:{1..3}", + "vllebrz v1,d12(x2,b2),m3:{1..3,6}", + "vlbr v1,d12(x2,b2),m3:{1..4}", + "vleb v1,d12(x2,b2),m3", + "vleh v1,d12(x2,b2),m3:{0..7}", + "vlef v1,d12(x2,b2),m3:{0..3}", + "vleg v1,d12(x2,b2),m3:{0,1}", + "vleib v1,i2:s16,m3", + "vleih v1,i2:s16,m3:{0..7}", + "vleif v1,i2:s16,m3:{0..3}", + "vleig v1,i2:s16,m3:{0,1}", + "vler v1,d12(x2,b2),m3:{0..3}", + "vlgv r1,v3,d12(b2),m4:{0..3}", + "vllez v1,d12(x2,b2),m3:{0..3,6}", + // "vlm v1,v3,d12(b2),m4", // cannot express constraint + "vlrlr v1,r3,d12(b2)", + "vlrl v1,d12(b2),i3:u8{0..15}", + "vlbb v1,d12(x2,b2),m3:{0..6}", + "vlvg v1,r3,d12(b2),m4:{0..3}", + "vlvgp v1,r2,r3", + "vll v1,r3,d12(b2)", + "vmrh v1,v2,v3,m4:{0..3}", + "vmrl v1,v2,v3,m4:{0..3}", + "vpk v1,v2,v3,m4:{1..3}", + "vpks v1,v2,v3,m4:{1..3},m5:{0,1}", // no spec. exception f... [truncated message content] |
From: Florian K. <fk...@so...> - 2025-03-05 23:13:06
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=69bc6d7cb08460006c404a8a9062e603ded1b457 commit 69bc6d7cb08460006c404a8a9062e603ded1b457 Author: Florian Krohm <fl...@ei...> Date: Wed Mar 5 23:12:17 2025 +0000 Fix two outdated comments in VEX. main_util.c: The symbol vg_message no longer exists. host_s390_defs.c: In b2cc7ea009ae4f0eaa1197ee6f5c07e0ee873b3a the definition of s390_host_hwcaps was moved to main_main.c Diff: --- VEX/priv/host_s390_defs.h | 2 +- VEX/priv/main_util.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index 9d844beeed..957585c396 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -907,7 +907,7 @@ VexInvalRange patchProfInc_S390(VexEndness endness_host, void *code_to_patch, const ULong *location_of_counter); -/* KLUDGE: See detailled comment in host_s390_defs.c. */ +/* KLUDGE: See detailled comment in main_main.c. */ extern UInt s390_host_hwcaps; /* Convenience macros to test installed facilities */ diff --git a/VEX/priv/main_util.c b/VEX/priv/main_util.c index 670de8b040..fffe4b4263 100644 --- a/VEX/priv/main_util.c +++ b/VEX/priv/main_util.c @@ -543,8 +543,7 @@ UInt vprintf_wrk ( void(*sink)(HChar), /* A general replacement for printf(). Note that only low-level - debugging info should be sent via here. The official route is to - to use vg_message(). This interface is deprecated. + debugging info should be sent via here. */ static HChar myprintf_buf[1000]; static Int n_myprintf_buf; |
From: Mark W. <ma...@so...> - 2025-03-05 23:06:59
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=c2138bcb4ccb6d805e1c11aad19dc25f6db2625d commit c2138bcb4ccb6d805e1c11aad19dc25f6db2625d Author: Andreas Schwab <sc...@su...> Date: Fri Jun 23 14:25:27 2023 +0200 riscv64: Avoid warning about missing return value in stat wrapper m_libcfile.c: In function 'vgPlain_stat': m_libcfile.c:594:1: error: control reaches end of non-void function [-Werror=return-type] 594 | } | ^ Diff: --- coregrind/m_libcfile.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c index e132e76597..767f34522c 100644 --- a/coregrind/m_libcfile.c +++ b/coregrind/m_libcfile.c @@ -557,6 +557,10 @@ SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf ) return res; } # endif +# if defined(VGP_riscv64_linux) + /* No fallback defined, statx syscall always exists. */ + return res; +# endif # elif defined(VGO_solaris) { # if defined(VGP_x86_solaris) |
From: Florian K. <fk...@so...> - 2025-03-05 22:35:55
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=989a0aedb1f3fb64653009b317509834ce206e2f commit 989a0aedb1f3fb64653009b317509834ce206e2f Author: Florian Krohm <fl...@ei...> Date: Wed Mar 5 22:35:01 2025 +0000 NEWS file: Sort fixed bugs by increasing bug number Diff: --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 85d83b51aa..ad58e72152 100644 --- a/NEWS +++ b/NEWS @@ -33,6 +33,7 @@ than mailing the developers (or mailing lists) directly -- bugs that are not entered into bugzilla tend to get forgotten about or ignored. 396415 Valgrind is not looking up $ORIGIN rpath of shebang programs +469782 Valgrind does not support zstd-compressed debug sections 487296 --track-fds=yes and --track-fds=all report erroneous information when fds 0, 1, or 2 are used as non-std 489913 WARNING: unhandled amd64-linux syscall: 444 (landlock_create_ruleset) @@ -43,14 +44,13 @@ are not entered into bugzilla tend to get forgotten about or ignored. 495816 s390x: Fix disassembler segfault for C[G]RT and CL[G]RT 496370 Illumos: signal handling is broken 496571 False positive for null key passed to bpf_map_get_next_key syscall. -469782 Valgrind does not support zstd-compressed debug sections 497130 Recognize new DWARF5 DW_LANG constants 497455 Update drd/scripts/download-and-build-gcc 497723 Enabling Ada demangling breaks callgrind differentiation between overloaded functions and procedures +498143 False positive on EVIOCGRAB ioctl 498317 FdBadUse is not a valid CoreError type in a suppression even though it's generated by --gen-suppressions=yes -498143 False positive on EVIOCGRAB ioctl 498492 none/tests/amd64/lzcnt64 crashes on FreeBSD compiled with clang 499183 FreeBSD: differences in avx-vmovq output 499212 mmap() with MAP_ALIGNED() returns unaligned pointer |
From: Florian K. <fk...@so...> - 2025-03-05 22:27:38
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=bef773e08f90948e555b026ae8970917cb182bd5 commit bef773e08f90948e555b026ae8970917cb182bd5 Author: Florian Krohm <fl...@ei...> Date: Wed Mar 5 22:24:32 2025 +0000 s390x: Add missing NEWS entry Add missing NEWS entry for https://bugs.kde.org/show_bug.cgi?id=495816 which was fixed in 1e694434a5cd2a0352e97f872ebd6922129c0282. Diff: --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index fb7642bb19..85d83b51aa 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 494327 Crash when running Helgrind built with #define TRACE_PTH_FNS 1 494337 All threaded applications cause still holding lock errors 495488 Add FreeBSD getrlimitusage syscall wrapper +495816 s390x: Fix disassembler segfault for C[G]RT and CL[G]RT 496370 Illumos: signal handling is broken 496571 False positive for null key passed to bpf_map_get_next_key syscall. 469782 Valgrind does not support zstd-compressed debug sections |
From: Mark W. <ma...@so...> - 2025-03-05 15:16:10
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=ec7335142384ec9da66871036803b96319b590eb commit ec7335142384ec9da66871036803b96319b590eb Author: Alexandra Hájková <aha...@re...> Date: Mon Mar 3 06:14:08 2025 -0500 syswrap-generic: Emit pp_ExeContext after the file descriptor backtrace Adjust use_after_close test for the change. (cherry picked from commit 838dc01d2c42f7f22785c771bd74bc4e595da444) Diff: --- coregrind/m_syswrap/syswrap-generic.c | 2 +- none/tests/use_after_close.stderr.exp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 1d80d09288..5222bcefe1 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -1179,6 +1179,7 @@ void fd_pp_Error (const Error *err) } VG_(emit)("%sFile descriptor %d %s%s\n", whatpre, nce->fd, error_string, whatpost); + VG_(pp_ExeContext)(where); /* If the file descriptor was never created we won't have where_closed and where_opened. Only print them in a use after close case. */ @@ -1190,7 +1191,6 @@ void fd_pp_Error (const Error *err) VG_(emit)("%sOriginally opened%s\n", auxpre, auxpost); VG_(pp_ExeContext)(nce->where_opened); } - VG_(pp_ExeContext)(where); } else { vg_assert2 (False, "Unknown error kind: %d", VG_(get_error_kind)(err)); diff --git a/none/tests/use_after_close.stderr.exp b/none/tests/use_after_close.stderr.exp index 1ef31c6551..75a8d66729 100644 --- a/none/tests/use_after_close.stderr.exp +++ b/none/tests/use_after_close.stderr.exp @@ -1,13 +1,13 @@ bad File descriptor 3 was closed already + at 0x........: write (in /...libc...) + by 0x........: main Previously closed at 0x........: close (in /...libc...) by 0x........: main Originally opened at 0x........: dup (in /...libc...) by 0x........: main - at 0x........: write (in /...libc...) - by 0x........: main File descriptor 7 was never created at 0x........: write (in /...libc...) by 0x........: main |
From: Mark W. <ma...@so...> - 2025-03-05 15:13:09
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=838dc01d2c42f7f22785c771bd74bc4e595da444 commit 838dc01d2c42f7f22785c771bd74bc4e595da444 Author: Alexandra Hájková <aha...@re...> Date: Mon Mar 3 06:14:08 2025 -0500 syswrap-generic: Emit pp_ExeContext after the file descriptor backtrace Adjust use_after_close test for the change. Diff: --- coregrind/m_syswrap/syswrap-generic.c | 2 +- none/tests/use_after_close.stderr.exp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 175c94b4d7..dea656aab2 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -1185,6 +1185,7 @@ void fd_pp_Error (const Error *err) } VG_(emit)("%sFile descriptor %d %s%s\n", whatpre, nce->fd, error_string, whatpost); + VG_(pp_ExeContext)(where); /* If the file descriptor was never created we won't have where_closed and where_opened. Only print them in a use after close case. */ @@ -1196,7 +1197,6 @@ void fd_pp_Error (const Error *err) VG_(emit)("%sOriginally opened%s\n", auxpre, auxpost); VG_(pp_ExeContext)(nce->where_opened); } - VG_(pp_ExeContext)(where); } else { vg_assert2 (False, "Unknown error kind: %d", VG_(get_error_kind)(err)); diff --git a/none/tests/use_after_close.stderr.exp b/none/tests/use_after_close.stderr.exp index 1ef31c6551..75a8d66729 100644 --- a/none/tests/use_after_close.stderr.exp +++ b/none/tests/use_after_close.stderr.exp @@ -1,13 +1,13 @@ bad File descriptor 3 was closed already + at 0x........: write (in /...libc...) + by 0x........: main Previously closed at 0x........: close (in /...libc...) by 0x........: main Originally opened at 0x........: dup (in /...libc...) by 0x........: main - at 0x........: write (in /...libc...) - by 0x........: main File descriptor 7 was never created at 0x........: write (in /...libc...) by 0x........: main |
From: Petr P. <pet...@da...> - 2025-03-03 21:06:30
|
On 2/25/25 11:27 PM, Mark Wielaard wrote: > Hi all, > > The riscv-linux port started by Petr Pavlu and discussed in > https://bugs.kde.org/show_bug.cgi?id=468575 > has finally been integrated into the main valgrind sources. Great to hear that. Thank you! > > We don't have a valgrind riscv arch maintainer yet (any volunteers?) I plan to continue contributing to the port. I've been quite busy lately but I hope things could improve in a few months. If anyone else is willing to help with the maintainership, it would be welcome. Cheers, Petr |
From: Jeff L. <jef...@gm...> - 2025-02-26 16:28:00
|
On 2/25/25 3:27 PM, Mark Wielaard wrote: > Hi all, > > The riscv-linux port started by Petr Pavlu and discussed in > https://bugs.kde.org/show_bug.cgi?id=468575 > has finally been integrated into the main valgrind sources. That's fantastic news. > > We don't have a valgrind riscv arch maintainer yet (any volunteers?) > but there are two buildbot builders: > https://builder.sourceware.org/buildbot/#/builders/valgrind-fedora-riscv > https://builder.sourceware.org/buildbot/#/builders/valgrind-ubuntu-riscv Petr would be the most logical choice in my mind, but I can't speak for his willingness and time. > > compressed.o: in function `test_compressed_10': > /var/lib/buildbot/workers/sourceware/valgrind-ubuntu-riscv/build/none/tests/riscv64/compressed.c:347:(.text+0x56d26): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20 > > integer.o: in function `test_integer_shared': > /var/lib/buildbot/workers/sourceware/valgrind-ubuntu-riscv/build/none/tests/riscv64/integer.c:81:(.text+0x22cdc): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20 Seems like either a test or toolchain problem. GIven it's C code I'd lean towards the latter. > > Also there seems to be an issue with larger programs with large stack > frames which I haven't tracked down yet. Definitely pass it along if it ultimately looks compiler related. We do certainly support larger stack frames, though we have to jump through some hoops to make them work. But I think once you get into the gigabyte ranges things might start to fall down. jeff |
From: Mark W. <ma...@kl...> - 2025-02-25 22:27:15
|
Hi all, The riscv-linux port started by Petr Pavlu and discussed in https://bugs.kde.org/show_bug.cgi?id=468575 has finally been integrated into the main valgrind sources. We don't have a valgrind riscv arch maintainer yet (any volunteers?) but there are two buildbot builders: https://builder.sourceware.org/buildbot/#/builders/valgrind-fedora-riscv https://builder.sourceware.org/buildbot/#/builders/valgrind-ubuntu-riscv The fedora builder runs on the starfive workers with Fedora release 40 (Forty) Linux 6.1.15-legacy-k1 GNU C Library (GNU libc) stable release version 2.39. gcc 14.1.1 binutils 2.42 The unbuntu builder runs on the bpi-f3 workers with Ubuntu 24.04.1 LTS Linux 6.8.0-52-generic Ubuntu GLIBC 2.39-0ubuntu8.3. gcc 14.2.0 GNU Binutils 2.43.1 The regtest results on the fedora setup look really good: == 748 tests, 1 stderr failure, 0 stdout failures, 0 stderrB failures, 1 stdoutB failure, 0 post failures == gdbserver_tests/hgtls (stdoutB) drd/tests/pth_mutex_signal (stderr) Unfortunately the ubuntu setup cannot build two of the new tests: compressed.o: in function `test_compressed_10': /var/lib/buildbot/workers/sourceware/valgrind-ubuntu-riscv/build/none/tests/riscv64/compressed.c:347:(.text+0x56d26): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20 integer.o: in function `test_integer_shared': /var/lib/buildbot/workers/sourceware/valgrind-ubuntu-riscv/build/none/tests/riscv64/integer.c:81:(.text+0x22cdc): dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20 Also there seems to be an issue with larger programs with large stack frames which I haven't tracked down yet. Testing and fixes highly appreciated. Cheers, Mark |
From: Mark W. <ma...@so...> - 2025-02-25 20:41:30
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=2d09ef48e22061b143cd4765e8defb63f5d5024a commit 2d09ef48e22061b143cd4765e8defb63f5d5024a Author: Mark Wielaard <ma...@kl...> Date: Sat Dec 28 01:29:58 2024 +0100 riscv64: Add hardwire for ld-linux-riscv64-lp64d.so.1 strcmp When using dlopen ld.so can end up in glibc strcmp_unaligned_loop which causes undefined reads. Hardwire strcmp for ld.so with a simple assembly implementation. Diff: --- coregrind/m_redir.c | 5 +++++ coregrind/m_trampoline.S | 17 +++++++++++++++++ coregrind/pub_core_trampoline.h | 1 + 3 files changed, 23 insertions(+) diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c index 958f3e7c46..5e7bc42f97 100644 --- a/coregrind/m_redir.c +++ b/coregrind/m_redir.c @@ -1714,6 +1714,11 @@ void VG_(redir_initialise) ( void ) (Addr)&VG_(riscv64_linux_REDIR_FOR_index), complain_about_stripped_glibc_ldso ); + add_hardwired_spec( + "ld-linux-riscv64-lp64d.so.1", "strcmp", + (Addr)&VG_(riscv64_linux_REDIR_FOR_strcmp), + complain_about_stripped_glibc_ldso + ); } # elif defined(VGP_x86_solaris) diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S index c506070d6a..4860a2259f 100644 --- a/coregrind/m_trampoline.S +++ b/coregrind/m_trampoline.S @@ -1647,6 +1647,23 @@ VG_(riscv64_linux_REDIR_FOR_index): ret .size VG_(riscv64_linux_REDIR_FOR_index), .-VG_(riscv64_linux_REDIR_FOR_index) +.global VG_(riscv64_linux_REDIR_FOR_strcmp) +.type VG_(riscv64_linux_REDIR_FOR_strcmp), @function +VG_(riscv64_linux_REDIR_FOR_strcmp): +0: + lbu a5, 0(a0) /* load *s1 */ + lbu a4, 0(a1) /* load *s2 */ + beqz a5, 1f /* check end of s1 */ + beq a5, a4, 2f /* loop if *s1 == *s2 */ +1: + subw a0, a5, a4 /* return value is *s1 - *s2 */ + ret +2: + addi a0, a0, 1 /* next char in s1 */ + addi a1, a1, 1 /* next char in s2 */ + j 0b /* and back to the start */ +.size VG_(riscv64_linux_REDIR_FOR_strcmp), .-VG_(riscv64_linux_REDIR_FOR_strcmp) + .global VG_(trampoline_stuff_end) VG_(trampoline_stuff_end): diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h index 7e9e2d76be..db497c51a5 100644 --- a/coregrind/pub_core_trampoline.h +++ b/coregrind/pub_core_trampoline.h @@ -180,6 +180,7 @@ extern UInt VG_(nanomips_linux_REDIR_FOR_strlen)( void* ); extern Addr VG_(riscv64_linux_SUBST_FOR_rt_sigreturn); extern HChar* VG_(riscv64_linux_REDIR_FOR_index)( const HChar*, Int ); extern SizeT VG_(riscv64_linux_REDIR_FOR_strlen)( const HChar* ); +extern Int VG_(riscv64_linux_REDIR_FOR_strcmp)( const HChar*, const HChar* ); #endif #if defined(VGP_x86_solaris) |
From: Mark W. <ma...@so...> - 2025-02-25 20:39:51
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=39704763eaded8590e4a34668191cd5bbd06e5a5 commit 39704763eaded8590e4a34668191cd5bbd06e5a5 Author: Mark Wielaard <ma...@kl...> Date: Thu Dec 26 13:18:09 2024 +0100 riscv64: syswrap various shared linux syscalls syswrap-riscv64-linux.c: Hook up open_tree, move_mount, fsopen, fsconfig, fsmount, fspick, pidfd_open, openat2, pidfd_getfd, epoll_pwait2, landlock_create_ruleset, landlock_add_rule, landlock_restrict_self and fchmodat2. Diff: --- coregrind/m_syswrap/syswrap-riscv64-linux.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/coregrind/m_syswrap/syswrap-riscv64-linux.c b/coregrind/m_syswrap/syswrap-riscv64-linux.c index 68c53b0bda..14310b2b2e 100644 --- a/coregrind/m_syswrap/syswrap-riscv64-linux.c +++ b/coregrind/m_syswrap/syswrap-riscv64-linux.c @@ -577,10 +577,24 @@ static SyscallTableEntry syscall_main_table[] = { LINXY(__NR_io_uring_setup, sys_io_uring_setup), /* 425 */ LINXY(__NR_io_uring_enter, sys_io_uring_enter), /* 426 */ LINXY(__NR_io_uring_register, sys_io_uring_register), /* 427 */ + LINXY(__NR_open_tree, sys_open_tree), /* 428 */ + LINX_(__NR_move_mount, sys_move_mount), /* 429 */ + LINXY(__NR_fsopen, sys_fsopen), /* 430 */ + LINX_(__NR_fsconfig, sys_fsconfig), /* 431 */ + LINXY(__NR_fsmount, sys_fsmount), /* 432 */ + LINXY(__NR_fspick, sys_fspick), /* 433 */ + LINXY(__NR_pidfd_open, sys_pidfd_open), /* 434 */ GENX_(__NR_clone3, sys_ni_syscall), /* 435 */ LINXY(__NR_close_range, sys_close_range), /* 436 */ + LINXY(__NR_openat2, sys_openat2), /* 437 */ + LINXY(__NR_pidfd_getfd, sys_pidfd_getfd), /* 438 */ LINX_(__NR_faccessat2, sys_faccessat2), /* 439 */ + LINXY(__NR_epoll_pwait2, sys_epoll_pwait2), /* 441 */ + LINXY(__NR_landlock_create_ruleset, sys_landlock_create_ruleset), /* 444 */ + LINX_(__NR_landlock_add_rule, sys_landlock_add_rule), /* 445 */ + LINX_(__NR_landlock_restrict_self, sys_landlock_restrict_self), /* 446 */ LINXY(__NR_memfd_secret, sys_memfd_secret), /* 447 */ + LINX_(__NR_fchmodat2, sys_fchmodat2), /* 452 */ }; SyscallTableEntry* ML_(get_linux_syscall_entry)(UInt sysno) |
From: Mark W. <ma...@so...> - 2025-02-25 20:38:23
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=e1fb410b5c72c89b6702e81aca91dee9250608ab commit e1fb410b5c72c89b6702e81aca91dee9250608ab Author: Mark Wielaard <ma...@kl...> Date: Sat Dec 14 22:11:57 2024 +0000 VEX/priv/guest_riscv64_toIR.c: Recognize both fence and fence.tso fence.tso is used for __atomic_thread_fence (__ATOMIC_ACQ_REL) There are 3 fence variants. fence.tso fm set to 1000 and pred and succ both set to 0011. fence with fm set to 0000 and pred and succ both set to 1111. fence with fm set to 0000 and pred and succ with some iorw flags set. https://bugs.kde.org/show_bug.cgi?id=468575#c42 Diff: --- VEX/priv/guest_riscv64_toIR.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/VEX/priv/guest_riscv64_toIR.c b/VEX/priv/guest_riscv64_toIR.c index 93ea5a173d..e76a602a0d 100644 --- a/VEX/priv/guest_riscv64_toIR.c +++ b/VEX/priv/guest_riscv64_toIR.c @@ -1610,19 +1610,26 @@ static Bool dis_RV64I(/*MB_OUT*/ DisResult* dres, } /* ------------------------ fence ------------------------ */ - if (INSN(19, 0) == 0b00000000000000001111 && INSN(31, 28) == 0b0000) { + if (INSN(19, 0) == 0b00000000000000001111) { + UInt fm = INSN(31, 28); UInt succ = INSN(23, 20); UInt pred = INSN(27, 24); - stmt(irsb, IRStmt_MBE(Imbe_Fence)); - if (pred == 0b1111 && succ == 0b1111) - DIP("fence\n"); - else - DIP("fence %s%s%s%s,%s%s%s%s\n", (pred & 0x8) ? "i" : "", - (pred & 0x4) ? "o" : "", (pred & 0x2) ? "r" : "", - (pred & 0x1) ? "w" : "", (succ & 0x8) ? "i" : "", - (succ & 0x4) ? "o" : "", (succ & 0x2) ? "r" : "", - (succ & 0x1) ? "w" : ""); - return True; + if ((fm == 0b1000 && pred == 0b0011 && succ == 0b0011) + || fm == 0b0000) + { + if (fm == 0b1000) + DIP("fence.tso\n"); + else if (pred == 0b1111 && succ == 0b1111) + DIP("fence\n"); + else + DIP("fence %s%s%s%s,%s%s%s%s\n", (pred & 0x8) ? "i" : "", + (pred & 0x4) ? "o" : "", (pred & 0x2) ? "r" : "", + (pred & 0x1) ? "w" : "", (succ & 0x8) ? "i" : "", + (succ & 0x4) ? "o" : "", (succ & 0x2) ? "r" : "", + (succ & 0x1) ? "w" : ""); + stmt(irsb, IRStmt_MBE(Imbe_Fence)); + return True; + } } /* ------------------------ ecall ------------------------ */ |
From: Mark W. <ma...@so...> - 2025-02-25 20:36:23
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=e54645bb7ad1147e6b14b3f7bcf648efe85c0036 commit e54645bb7ad1147e6b14b3f7bcf648efe85c0036 Author: Mark Wielaard <ma...@kl...> Date: Wed Dec 25 00:36:53 2024 +0100 none/tests/riscv64/integer.c: replace zero by a1 Using zero will produce an gas Error: illegal operands `la zero,0' https://sourceware.org/bugzilla/show_bug.cgi?id=32496 Simplest seems to be to replace the usage of "zero" in the branch instruction tests by "a1". It seems that does test something similar that isn't tested before. Diff: --- none/tests/riscv64/integer.c | 48 +++++++++--------- none/tests/riscv64/integer.stdout.exp | 96 +++++++++++++++++------------------ 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/none/tests/riscv64/integer.c b/none/tests/riscv64/integer.c index d0c8828e9d..0b5638b237 100644 --- a/none/tests/riscv64/integer.c +++ b/none/tests/riscv64/integer.c @@ -129,10 +129,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "beq a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "beq a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "beq zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "beq zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "beq a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "beq a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "beq a0, a1, 1f", -1, -1, a0, a1); @@ -142,10 +142,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "bne a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bne a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bne zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "bne zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bne a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "bne a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bne a0, a1, 1f", -1, -1, a0, a1); @@ -155,10 +155,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "blt a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "blt a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "blt zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "blt zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "blt a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "blt a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "blt a0, a1, 1f", -1, -1, a0, a1); @@ -168,10 +168,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "bge a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bge a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bge zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "bge zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bge a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "bge a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bge a0, a1, 1f", -1, -1, a0, a1); @@ -181,10 +181,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "bltu a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bltu a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bltu zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "bltu zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bltu a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "bltu a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bltu a0, a1, 1f", -1, -1, a0, a1); @@ -194,10 +194,10 @@ static void test_integer_shared(void) TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 0, 1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 1, 1, a0, a1); - TESTINST_0_2_Bxx_COND(4, "bgeu a0, zero, 1f", 0, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bgeu a0, zero, 1f", 1, 0, a0, zero); - TESTINST_0_2_Bxx_COND(4, "bgeu zero, a0, 1f", 0, 0, zero, a0); - TESTINST_0_2_Bxx_COND(4, "bgeu zero, a0, 1f", 0, 1, zero, a0); + TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 0, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 1, 0, a0, a1); + TESTINST_0_2_Bxx_COND(4, "bgeu a1, a0, 1f", 0, 0, a1, a0); + TESTINST_0_2_Bxx_COND(4, "bgeu a1, a0, 1f", 0, 1, a1, a0); TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", 0, -1, a0, a1); TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", -1, 0, a0, a1); TESTINST_0_2_Bxx_COND(4, "bgeu a0, a1, 1f", -1, -1, a0, a1); diff --git a/none/tests/riscv64/integer.stdout.exp b/none/tests/riscv64/integer.stdout.exp index 6a3bf8936c..1a4d89b7a2 100644 --- a/none/tests/riscv64/integer.stdout.exp +++ b/none/tests/riscv64/integer.stdout.exp @@ -292,17 +292,17 @@ beq a0, a1, 1f :: beq a0, a1, 1f :: inputs: a0=1, a1=1 branch: taken -beq a0, zero, 1f :: - inputs: a0=0, zero=0 +beq a0, a1, 1f :: + inputs: a0=0, a1=0 branch: taken -beq a0, zero, 1f :: - inputs: a0=1, zero=0 +beq a0, a1, 1f :: + inputs: a0=1, a1=0 branch: not taken -beq zero, a0, 1f :: - inputs: zero=0, a0=0 +beq a1, a0, 1f :: + inputs: a1=0, a0=0 branch: taken -beq zero, a0, 1f :: - inputs: zero=0, a0=1 +beq a1, a0, 1f :: + inputs: a1=0, a0=1 branch: not taken beq a0, a1, 1f :: inputs: a0=0, a1=-1 @@ -325,17 +325,17 @@ bne a0, a1, 1f :: bne a0, a1, 1f :: inputs: a0=1, a1=1 branch: not taken -bne a0, zero, 1f :: - inputs: a0=0, zero=0 +bne a0, a1, 1f :: + inputs: a0=0, a1=0 branch: not taken -bne a0, zero, 1f :: - inputs: a0=1, zero=0 +bne a0, a1, 1f :: + inputs: a0=1, a1=0 branch: taken -bne zero, a0, 1f :: - inputs: zero=0, a0=0 +bne a1, a0, 1f :: + inputs: a1=0, a0=0 branch: not taken -bne zero, a0, 1f :: - inputs: zero=0, a0=1 +bne a1, a0, 1f :: + inputs: a1=0, a0=1 branch: taken bne a0, a1, 1f :: inputs: a0=0, a1=-1 @@ -358,17 +358,17 @@ blt a0, a1, 1f :: blt a0, a1, 1f :: inputs: a0=1, a1=1 branch: not taken -blt a0, zero, 1f :: - inputs: a0=0, zero=0 +blt a0, a1, 1f :: + inputs: a0=0, a1=0 branch: not taken -blt a0, zero, 1f :: - inputs: a0=1, zero=0 +blt a0, a1, 1f :: + inputs: a0=1, a1=0 branch: not taken -blt zero, a0, 1f :: - inputs: zero=0, a0=0 +blt a1, a0, 1f :: + inputs: a1=0, a0=0 branch: not taken -blt zero, a0, 1f :: - inputs: zero=0, a0=1 +blt a1, a0, 1f :: + inputs: a1=0, a0=1 branch: taken blt a0, a1, 1f :: inputs: a0=0, a1=-1 @@ -391,17 +391,17 @@ bge a0, a1, 1f :: bge a0, a1, 1f :: inputs: a0=1, a1=1 branch: taken -bge a0, zero, 1f :: - inputs: a0=0, zero=0 +bge a0, a1, 1f :: + inputs: a0=0, a1=0 branch: taken -bge a0, zero, 1f :: - inputs: a0=1, zero=0 +bge a0, a1, 1f :: + inputs: a0=1, a1=0 branch: taken -bge zero, a0, 1f :: - inputs: zero=0, a0=0 +bge a1, a0, 1f :: + inputs: a1=0, a0=0 branch: taken -bge zero, a0, 1f :: - inputs: zero=0, a0=1 +bge a1, a0, 1f :: + inputs: a1=0, a0=1 branch: not taken bge a0, a1, 1f :: inputs: a0=0, a1=-1 @@ -424,17 +424,17 @@ bltu a0, a1, 1f :: bltu a0, a1, 1f :: inputs: a0=1, a1=1 branch: not taken -bltu a0, zero, 1f :: - inputs: a0=0, zero=0 +bltu a0, a1, 1f :: + inputs: a0=0, a1=0 branch: not taken -bltu a0, zero, 1f :: - inputs: a0=1, zero=0 +bltu a0, a1, 1f :: + inputs: a0=1, a1=0 branch: not taken -bltu zero, a0, 1f :: - inputs: zero=0, a0=0 +bltu a1, a0, 1f :: + inputs: a1=0, a0=0 branch: not taken -bltu zero, a0, 1f :: - inputs: zero=0, a0=1 +bltu a1, a0, 1f :: + inputs: a1=0, a0=1 branch: taken bltu a0, a1, 1f :: inputs: a0=0, a1=-1 @@ -457,17 +457,17 @@ bgeu a0, a1, 1f :: bgeu a0, a1, 1f :: inputs: a0=1, a1=1 branch: taken -bgeu a0, zero, 1f :: - inputs: a0=0, zero=0 +bgeu a0, a1, 1f :: + inputs: a0=0, a1=0 branch: taken -bgeu a0, zero, 1f :: - inputs: a0=1, zero=0 +bgeu a0, a1, 1f :: + inputs: a0=1, a1=0 branch: taken -bgeu zero, a0, 1f :: - inputs: zero=0, a0=0 +bgeu a1, a0, 1f :: + inputs: a1=0, a0=0 branch: taken -bgeu zero, a0, 1f :: - inputs: zero=0, a0=1 +bgeu a1, a0, 1f :: + inputs: a1=0, a0=1 branch: not taken bgeu a0, a1, 1f :: inputs: a0=0, a1=-1 |
From: LATHUILIERE B. <bru...@ed...> - 2025-02-25 17:58:48
|
Hello everyone, I recently discovered a bug in verrou regarding fma on arm64 architecture. More specifically it comes from Iop_MSubF64 and Iop_MSubF32. In the file VEX/pub/libvex_ir.h the definition of MAddF32 and MSubF32 is arg2 * arg3 - arg4, but in the file VEX/priv/guest_arm64_toIR.c a different definition is used - arg2*arg3+ arg4. Valgrind does not see the problem because the same definition is used in host part. I have fixed this problem with the patch: https://raw.githubusercontent.com/edf-hpc/verrou/refs/heads/master/valgrind.fma_arm64.diff Some notes about the patch : - Not ready for valgrind integration yet, but I share it now since it is needed to write floating-point tools. - In guest_arm64_toIR.c I only use Iop_Madd32/64 and Iop_NegF32/64 to avoid the MSub problem. - I also solve another problem with vectorized FMA (I only make one patch as the two bugs affect the same lines). In the current implementation, vectorized fma generates an ADD and a MUL Iop, which leads to rounding problems. As for amd64 arch I unroll the vectorization to use scalar MAdd Iop. Since the results are modified, I updated the unit test to be consistent with native execution. The patch fixes the problem, but is not clean enough for integration : - Do we need to keep MSub Iops? - Do we want to introduce NegMSub and NegMAdd Iop like for F128? - Do we want to introduce the vectorized version of FMA to avoid unrolling and performance loss? What's your opinion about FMA Iops? Since it was painful to discover the bug so late, I wanted to improve my test coverage. To do this, I want to run all the test-cases from other tools (the ones that do not modify the standard output, especially none) with the verrou tool and default options (to avoid modifying the results). To do this, I have patched the tests/vg_regtest.in file to add new options : --force-tool= to specify a tool (not the one detected from the test cas path). --stderr-ignore to ignore stderr comparison (verrou and none stderr output are not the same) --toolopt-ignore to ignore the tool option defined in the test case (callgrind uses options that are not recognized by verrou) --post-ignore , --clean-ignore to ignore the post and clean step (verrou and callgrind l do not generate the same files ) The simplest use case is : perl ./tests/vg_regtest none/tests --force-tool=verrou --stderr-ignore For none tool, this approach is really convenient, but for tools that define multiple test-cases with the same binary and the same input it means multiple runs of equivalent test-cases. The patch is available there: https://raw.githubusercontent.com/edf-hpc/verrou/refs/heads/master/valgrind.vgregtest.diff I can maintain the patch in verrou repo, but if it is useful to anyone, we can consider integration. Do you think it can be useful for other tools? ++ Bruno Ce message et toutes les pièces jointes (ci-après le 'Message') sont établis à l'intention exclusive des destinataires et les informations qui y figurent sont strictement confidentielles. Toute utilisation de ce Message non conforme à sa destination, toute diffusion ou toute publication totale ou partielle, est interdite sauf autorisation expresse. Si vous n'êtes pas le destinataire de ce Message, il vous est interdit de le copier, de le faire suivre, de le divulguer ou d'en utiliser tout ou partie. Si vous avez reçu ce Message par erreur, merci de le supprimer de votre système, ainsi que toutes ses copies, et de n'en garder aucune trace sur quelque support que ce soit. Nous vous remercions également d'en avertir immédiatement l'expéditeur par retour du message. Il est impossible de garantir que les communications par messagerie électronique arrivent en temps utile, sont sécurisées ou dénuées de toute erreur ou virus. ____________________________________________________ This message and any attachments (the 'Message') are intended solely for the addressees. The information contained in this Message is confidential. Any use of information contained in this Message not in accord with its purpose, any dissemination or disclosure, either whole or partial, is prohibited except formal approval. If you are not the addressee, you may not copy, forward, disclose or use any part of it. If you have received this message in error, please delete it and all copies from your system and notify the sender immediately by return message. E-mail communication cannot be guaranteed to be timely secure, error or virus-free. |
From: Mark W. <ma...@so...> - 2025-02-25 16:53:03
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=e3432fc94d5dc2164d130194dd36a98bd770d593 commit e3432fc94d5dc2164d130194dd36a98bd770d593 Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:43 2023 +0000 riscv64: Add initial support: test modifications The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> Some integration fixes were added by Mark Wielaard <ma...@kl...> - helgrind/tests/tc11_XCHG.c: Fix XCHG_M_R guard https://bugs.kde.org/show_bug.cgi?id=493507 Diff: --- helgrind/tests/annotate_hbefore.c | 30 +++++++++++++ helgrind/tests/tc07_hbl1.c | 10 +++++ helgrind/tests/tc08_hbl2.c | 10 +++++ helgrind/tests/tc11_XCHG.c | 6 ++- memcheck/tests/Makefile.am | 5 ++- memcheck/tests/atomic_incs.c | 78 ++++++++++++++++++++++++++++++++- memcheck/tests/leak-segv-jmp.c | 19 +++++++- memcheck/tests/leak-segv-jmp.stderr.exp | 20 ++++----- memcheck/tests/leak.h | 5 +++ none/tests/Makefile.am | 13 +++++- none/tests/allexec_prepare_prereq | 1 + none/tests/faultstatus.c | 4 +- none/tests/libvex_test.c | 7 ++- tests/arch_test.c | 5 +++ tests/platform_test | 1 + 15 files changed, 195 insertions(+), 19 deletions(-) diff --git a/helgrind/tests/annotate_hbefore.c b/helgrind/tests/annotate_hbefore.c index 259d3b64c8..52dce3e76e 100644 --- a/helgrind/tests/annotate_hbefore.c +++ b/helgrind/tests/annotate_hbefore.c @@ -314,6 +314,36 @@ UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) return success; } +#elif defined(VGA_riscv64) + +// riscv64 +/* return 1 if success, 0 if failure */ +UWord do_acasW ( UWord* addr, UWord expected, UWord nyu ) +{ + UWord success; + UWord block[3] = { (UWord)addr, nyu, expected}; + + __asm__ __volatile__( + "ld t0, 0(%1)" "\n\t" + "ld t2, 16(%1)" "\n\t" + "ld t3, 8(%1)" "\n\t" + "lr.d t1, 0(t0)" "\n\t" + "bne t1, t2, 1f" "\n\t" + "sc.d t1, t3, 0(t0)" "\n\t" + "xori %0, t1, 1" "\n\t" + "j 2f" "\n\t" + "1:" "\n\t" + "mv %0, zero" "\n\t" + "2:" "\n\t" + : /*out*/ "=r"(success) + : /*in*/ "r"(&block[0]) + : /*trash*/ "t0", "t1", "t2", "t3", "memory" + ); + + assert(success == 0 || success == 1); + return success; +} + #endif void atomic_incW ( UWord* w ) diff --git a/helgrind/tests/tc07_hbl1.c b/helgrind/tests/tc07_hbl1.c index a4250c62c4..ee0564d20d 100644 --- a/helgrind/tests/tc07_hbl1.c +++ b/helgrind/tests/tc07_hbl1.c @@ -19,6 +19,7 @@ #undef PLAT_arm64_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux +#undef PLAT_riscv64_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris @@ -50,6 +51,8 @@ # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__nanomips__) # define PLAT_nanomips_linux 1 +#elif defined(__linux__) && defined(__riscv) && (__riscv_xlen == 64) +# define PLAT_riscv64_linux 1 #elif defined(__sun__) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun__) && defined(__x86_64__) @@ -134,6 +137,13 @@ : /*out*/ : /*in*/ "r"(&(_lval)) \ : /*trash*/ "$t0", "$t1", "memory" \ ) +#elif defined(PLAT_riscv64_linux) +# define INC(_lval,_lqual) \ + __asm__ __volatile__ ( \ + " amoadd.w zero, %1, (%0)\n" \ + : /*out*/ : /*in*/ "r"(&(_lval)), "r"(1) \ + : /*trash*/ "memory" \ + ) #else # error "Fix Me for this platform" #endif diff --git a/helgrind/tests/tc08_hbl2.c b/helgrind/tests/tc08_hbl2.c index 6a8543fa1d..be2b78b01c 100644 --- a/helgrind/tests/tc08_hbl2.c +++ b/helgrind/tests/tc08_hbl2.c @@ -36,6 +36,7 @@ #undef PLAT_s390x_linux #undef PLAT_mips32_linux #undef PLAT_mips64_linux +#undef PLAT_riscv64_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris @@ -71,6 +72,8 @@ #endif #elif defined(__linux__) && defined(__nanomips__) # define PLAT_nanomips_linux 1 +#elif defined(__linux__) && defined(__riscv) && (__riscv_xlen == 64) +# define PLAT_riscv64_linux 1 #elif defined(__sun__) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun__) && defined(__x86_64__) @@ -154,6 +157,13 @@ : /*out*/ : /*in*/ "r"(&(_lval)) \ : /*trash*/ "$t0", "$t1", "memory" \ ) +#elif defined(PLAT_riscv64_linux) +# define INC(_lval,_lqual) \ + __asm__ __volatile__ ( \ + " amoadd.w zero, %1, (%0)\n" \ + : /*out*/ : /*in*/ "r"(&(_lval)), "r"(1) \ + : /*trash*/ "memory" \ + ) #else # error "Fix Me for this platform" #endif diff --git a/helgrind/tests/tc11_XCHG.c b/helgrind/tests/tc11_XCHG.c index cc00ba38fe..e92b671b7e 100644 --- a/helgrind/tests/tc11_XCHG.c +++ b/helgrind/tests/tc11_XCHG.c @@ -21,6 +21,7 @@ #undef PLAT_arm_linux #undef PLAT_s390x_linux #undef PLAT_mips32_linux +#undef PLAT_riscv64_linux #undef PLAT_x86_solaris #undef PLAT_amd64_solaris @@ -52,6 +53,8 @@ # define PLAT_mips32_linux 1 #elif defined(__linux__) && defined(__nanomips__) # define PLAT_nanomips_linux 1 +#elif defined(__linux__) && defined(__riscv) && (__riscv_xlen == 64) +# define PLAT_riscv64_linux 1 #elif defined(__sun__) && defined(__i386__) # define PLAT_x86_solaris 1 #elif defined(__sun__) && defined(__x86_64__) @@ -128,7 +131,8 @@ #elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux) \ || defined(PLAT_arm_linux) || defined(PLAT_arm64_linux) \ - || defined(PLAT_arm64_freebsd) + || defined(PLAT_arm64_freebsd) \ + || defined(PLAT_riscv64_linux) # if defined(HAVE_BUILTIN_ATOMIC) # define XCHG_M_R(_addr,_lval) \ do { \ diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index bfdd86c7e3..a4ca2853fb 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -53,6 +53,9 @@ endif if VGCONF_PLATFORMS_INCLUDE_ARM64_LINUX SUBDIRS += arm64-linux endif +if VGCONF_PLATFORMS_INCLUDE_RISCV64_LINUX +SUBDIRS += riscv64-linux +endif if VGCONF_PLATFORMS_INCLUDE_X86_SOLARIS SUBDIRS += x86-solaris endif @@ -67,7 +70,7 @@ SUBDIRS += amd64-freebsd endif DIST_SUBDIRS = x86 amd64 arm64 ppc32 ppc64 s390x linux \ - darwin solaris x86-linux amd64-linux arm64-linux \ + darwin solaris x86-linux amd64-linux arm64-linux riscv64-linux \ x86-solaris amd64-solaris mips32 mips64 \ freebsd amd64-freebsd x86-freebsd \ common . diff --git a/memcheck/tests/atomic_incs.c b/memcheck/tests/atomic_incs.c index 1c738c530d..89b6e1f757 100644 --- a/memcheck/tests/atomic_incs.c +++ b/memcheck/tests/atomic_incs.c @@ -245,6 +245,26 @@ __attribute__((noinline)) void atomic_add_8bit ( char* p, int n ) ); } while (block[2] != 1); #endif +#elif defined(VGA_riscv64) + unsigned long long int block[3] + = { (unsigned long long int)p, (unsigned long long int)n, + 0xFFFFFFFFFFFFFFFFULL}; + do { + __asm__ __volatile__( + "mv t0, %0" "\n\t" + "ld t1, (t0)" "\n\t" // p + "ld t2, 8(t0)" "\n\t" // n + "lr.w t3, (t1)" "\n\t" + "slli t3, t3, 56" "\n\t" // sign-extend + "srai t3, t3, 56" "\n\t" + "add t3, t3, t2" "\n\t" + "sc.w t4, t3, (t1)" "\n\t" + "sd t4, 16(t0)" "\n\t" + : /*out*/ + : /*in*/ "r"(&block[0]) + : /*trash*/ "memory", "t0", "t1", "t2", "t3", "t4" + ); + } while (block[2] != 0); #else # error "Unsupported arch" #endif @@ -461,6 +481,26 @@ __attribute__((noinline)) void atomic_add_16bit ( short* p, int n ) ); } while (block[2] != 1); #endif +#elif defined(VGA_riscv64) + unsigned long long int block[3] + = { (unsigned long long int)p, (unsigned long long int)n, + 0xFFFFFFFFFFFFFFFFULL}; + do { + __asm__ __volatile__( + "mv t0, %0" "\n\t" + "ld t1, (t0)" "\n\t" // p + "ld t2, 8(t0)" "\n\t" // n + "lr.w t3, (t1)" "\n\t" + "slli t3, t3, 48" "\n\t" // sign-extend + "srai t3, t3, 48" "\n\t" + "add t3, t3, t2" "\n\t" + "sc.w t4, t3, (t1)" "\n\t" + "sd t4, 16(t0)" "\n\t" + : /*out*/ + : /*in*/ "r"(&block[0]) + : /*trash*/ "memory", "t0", "t1", "t2", "t3", "t4" + ); + } while (block[2] != 0); #else # error "Unsupported arch" #endif @@ -616,6 +656,24 @@ __attribute__((noinline)) void atomic_add_32bit ( int* p, int n ) : /*trash*/ "memory", "t0", "t1", "t2", "t3" ); } while (block[2] != 1); +#elif defined(VGA_riscv64) + unsigned long long int block[3] + = { (unsigned long long int)p, (unsigned long long int)n, + 0xFFFFFFFFFFFFFFFFULL}; + do { + __asm__ __volatile__( + "mv t0, %0" "\n\t" + "ld t1, (t0)" "\n\t" // p + "ld t2, 8(t0)" "\n\t" // n + "lr.w t3, (t1)" "\n\t" + "add t3, t3, t2" "\n\t" + "sc.w t4, t3, (t1)" "\n\t" + "sd t4, 16(t0)" "\n\t" + : /*out*/ + : /*in*/ "r"(&block[0]) + : /*trash*/ "memory", "t0", "t1", "t2", "t3", "t4" + ); + } while (block[2] != 0); #else # error "Unsupported arch" #endif @@ -718,6 +776,24 @@ __attribute__((noinline)) void atomic_add_64bit ( long long int* p, int n ) : /*trash*/ "memory", "t0", "t1", "t2", "t3" ); } while (block[2] != 1); +#elif defined(VGA_riscv64) + unsigned long long int block[3] + = { (unsigned long long int)p, (unsigned long long int)n, + 0xFFFFFFFFFFFFFFFFULL}; + do { + __asm__ __volatile__( + "mv t0, %0" "\n\t" + "ld t1, (t0)" "\n\t" // p + "ld t2, 8(t0)" "\n\t" // n + "lr.d t3, (t1)" "\n\t" + "add t3, t3, t2" "\n\t" + "sc.d t4, t3, (t1)" "\n\t" + "sd t4, 16(t0)" "\n\t" + : /*out*/ + : /*in*/ "r"(&block[0]) + : /*trash*/ "memory", "t0", "t1", "t2", "t3", "t4" + ); + } while (block[2] != 0); #else # error "Unsupported arch" #endif @@ -731,7 +807,7 @@ __attribute__((noinline)) void atomic_add_128bit ( MyU128* p, || defined(VGA_amd64) \ || defined(VGA_ppc64be) || defined(VGA_ppc64le) \ || defined(VGA_arm) \ - || defined(VGA_s390x) + || defined(VGA_s390x) || defined(VGA_riscv64) /* do nothing; is not supported */ #elif defined(VGA_arm64) unsigned long long int block[3] diff --git a/memcheck/tests/leak-segv-jmp.c b/memcheck/tests/leak-segv-jmp.c index 30fe2a1a99..15cc9f8fb2 100644 --- a/memcheck/tests/leak-segv-jmp.c +++ b/memcheck/tests/leak-segv-jmp.c @@ -183,6 +183,23 @@ extern UWord do_syscall_WRK ( return out; } +#elif defined(VGP_riscv64_linux) +extern UWord do_syscall_WRK ( + UWord a1, UWord a2, UWord a3, + UWord a4, UWord a5, UWord a6, + UWord syscall_no + ); +asm( +".text\n" +".globl do_syscall_WRK\n" +"do_syscall_WRK:\n" +" mv a7, a6\n" +" li a6, 0\n" +" ecall\n" +" ret\n" +".previous\n" +); + #elif defined(VGP_x86_solaris) extern ULong do_syscall_WRK(UWord a1, UWord a2, UWord a3, @@ -369,7 +386,7 @@ static void non_simd_mprotect (long tid, void* addr, long len) &err); if (err) mprotect_result = -1; -#elif defined(VGP_arm64_linux) +#elif defined(VGP_arm64_linux) || defined(VGP_riscv64_linux) mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE, 0, 0, 0, __NR_mprotect); diff --git a/memcheck/tests/leak-segv-jmp.stderr.exp b/memcheck/tests/leak-segv-jmp.stderr.exp index 147bdf8cdf..e18418d440 100644 --- a/memcheck/tests/leak-segv-jmp.stderr.exp +++ b/memcheck/tests/leak-segv-jmp.stderr.exp @@ -14,8 +14,8 @@ To see them, rerun with: --leak-check=full --show-leak-kinds=all expecting a leak 1,000 bytes in 1 blocks are definitely lost in loss record ... of ... at 0x........: malloc (vg_replace_malloc.c:...) - by 0x........: f (leak-segv-jmp.c:420) - by 0x........: main (leak-segv-jmp.c:495) + by 0x........: f (leak-segv-jmp.c:437) + by 0x........: main (leak-segv-jmp.c:512) LEAK SUMMARY: definitely lost: 1,000 bytes in 1 blocks @@ -30,8 +30,8 @@ mprotect result 0 expecting a leak again 1,000 bytes in 1 blocks are definitely lost in loss record ... of ... at 0x........: malloc (vg_replace_malloc.c:...) - by 0x........: f (leak-segv-jmp.c:420) - by 0x........: main (leak-segv-jmp.c:495) + by 0x........: f (leak-segv-jmp.c:437) + by 0x........: main (leak-segv-jmp.c:512) LEAK SUMMARY: definitely lost: 1,000 bytes in 1 blocks @@ -46,8 +46,8 @@ full mprotect result 0 expecting a leak again after full mprotect 1,000 bytes in 1 blocks are definitely lost in loss record ... of ... at 0x........: malloc (vg_replace_malloc.c:...) - by 0x........: f (leak-segv-jmp.c:420) - by 0x........: main (leak-segv-jmp.c:495) + by 0x........: f (leak-segv-jmp.c:437) + by 0x........: main (leak-segv-jmp.c:512) LEAK SUMMARY: definitely lost: 1,000 bytes in 1 blocks @@ -62,13 +62,13 @@ mprotect result 0 expecting heuristic not to crash after full mprotect 1,000 bytes in 1 blocks are definitely lost in loss record ... of ... at 0x........: malloc (vg_replace_malloc.c:...) - by 0x........: f (leak-segv-jmp.c:420) - by 0x........: main (leak-segv-jmp.c:495) + by 0x........: f (leak-segv-jmp.c:437) + by 0x........: main (leak-segv-jmp.c:512) 200,000 bytes in 1 blocks are possibly lost in loss record ... of ... at 0x........: calloc (vg_replace_malloc.c:...) - by 0x........: f (leak-segv-jmp.c:467) - by 0x........: main (leak-segv-jmp.c:495) + by 0x........: f (leak-segv-jmp.c:484) + by 0x........: main (leak-segv-jmp.c:512) LEAK SUMMARY: definitely lost: 1,000 bytes in 1 blocks diff --git a/memcheck/tests/leak.h b/memcheck/tests/leak.h index bf78d5866f..f9a2db290d 100644 --- a/memcheck/tests/leak.h +++ b/memcheck/tests/leak.h @@ -181,6 +181,11 @@ __asm__ __volatile__ ("mov x17, 0\n\t"); \ __asm__ __volatile__ ("mov x18, 0\n\t"); \ } while (0) +#elif defined(__riscv) +#define CLEAR_CALLER_SAVED_REGS \ + do { \ + __asm__ __volatile__( "li a0, 0" : : :/*trash*/"a0" ); \ + } while (0) #else #define CLEAR_CALLER_SAVED_REGS /*nothing*/ #endif diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am index 7ceb0052b4..d119c74a1d 100644 --- a/none/tests/Makefile.am +++ b/none/tests/Makefile.am @@ -35,6 +35,9 @@ endif if VGCONF_ARCHS_INCLUDE_NANOMIPS SUBDIRS += nanomips endif +if VGCONF_ARCHS_INCLUDE_RISCV64 +SUBDIRS += riscv64 +endif # OS-specific tests @@ -75,8 +78,9 @@ SUBDIRS += x86-freebsd endif DIST_SUBDIRS = x86 amd64 ppc32 ppc64 arm arm64 s390x mips32 mips64 nanomips \ - linux darwin solaris freebsd amd64-linux x86-linux amd64-darwin \ - x86-darwin amd64-solaris x86-solaris x86-freebsd scripts . + riscv64 linux darwin solaris freebsd amd64-linux x86-linux \ + amd64-darwin x86-darwin amd64-solaris x86-solaris x86-freebsd \ + scripts . dist_noinst_SCRIPTS = \ filter_cmdline0 \ @@ -401,6 +405,11 @@ libvex_test_CFLAGS = $(AM_CFLAGS) @FLAG_FSANITIZE@ libvex_test_LDADD = ../../VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a \ @LIB_UBSAN@ libvexmultiarch_test_CFLAGS= $(AM_CFLAGS) @FLAG_FSANITIZE@ +if VGCONF_ARCHS_INCLUDE_RISCV64 +# Disable RISC-V linker relaxation, it takes GNU ld 2.39 tens of minutes to sort +# it through on this large test. +libvexmultiarch_test_LDFLAGS = -Wl,--no-relax +endif libvexmultiarch_test_LDADD = \ ../../VEX/libvexmultiarch-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a \ ../../VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a @LIB_UBSAN@ diff --git a/none/tests/allexec_prepare_prereq b/none/tests/allexec_prepare_prereq index a541f42994..fa4d317069 100755 --- a/none/tests/allexec_prepare_prereq +++ b/none/tests/allexec_prepare_prereq @@ -34,5 +34,6 @@ pair s390x_unexisting_in_32bits s390x pair arm arm64 pair mips32 mips64 pair nanomips nanoMIPS_unexisting_in_64bits +pair riscv_unexisting_in_32bits riscv64 exit 0 diff --git a/none/tests/faultstatus.c b/none/tests/faultstatus.c index 9e262395bc..a83546b54b 100644 --- a/none/tests/faultstatus.c +++ b/none/tests/faultstatus.c @@ -11,7 +11,7 @@ #include "../../config.h" /* Division by zero triggers a SIGFPE on x86 and x86_64, - but not on the PowerPC architecture. + but not on the PowerPC, AArch64 and RISC-V architectures. On ARM-Linux, we do get a SIGFPE, but not from the faulting of a division instruction (there isn't any such thing) but rather @@ -19,7 +19,7 @@ Hence we get a SIGFPE but the SI_CODE is different from that on x86/amd64-linux. */ -#if defined(__powerpc__) || defined(__aarch64__) +#if defined(__powerpc__) || defined(__aarch64__) || defined(__riscv) # define DIVISION_BY_ZERO_TRIGGERS_FPE 0 #if defined(VGO_freebsd) # define DIVISION_BY_ZERO_SI_CODE SI_LWP diff --git a/none/tests/libvex_test.c b/none/tests/libvex_test.c index 5b57a4c2e2..6a8086aced 100644 --- a/none/tests/libvex_test.c +++ b/none/tests/libvex_test.c @@ -76,6 +76,8 @@ __attribute__((noinline)) static void get_guest_arch(VexArch *ga) *ga = VexArchMIPS64; #elif defined(VGA_nanomips) *ga = VexArchNANOMIPS; +#elif defined(VGA_riscv64) + *ga = VexArchRISCV64; #else missing arch; #endif @@ -113,6 +115,7 @@ static VexEndness arch_endness (VexArch va) { else return VexEndnessBE; } + case VexArchRISCV64: return VexEndnessLE; default: failure_exit(); } } @@ -139,6 +142,7 @@ static UInt arch_hwcaps (VexArch va) { case VexArchMIPS64: return VEX_PRID_COMP_MIPS | VEX_MIPS_HOST_FR; #endif case VexArchNANOMIPS: return 0; + case VexArchRISCV64: return 0; default: failure_exit(); } } @@ -156,6 +160,7 @@ static Bool mode64 (VexArch va) { case VexArchMIPS32: return False; case VexArchMIPS64: return True; case VexArchNANOMIPS: return False; + case VexArchRISCV64: return True; default: failure_exit(); } } @@ -275,7 +280,7 @@ int main(int argc, char **argv) // explicitly via command line arguments. if (multiarch) { VexArch va; - for (va = VexArchX86; va <= VexArchNANOMIPS; va++) { + for (va = VexArchX86; va <= VexArchRISCV64; va++) { vta.arch_host = va; vta.archinfo_host.endness = arch_endness (vta.arch_host); vta.archinfo_host.hwcaps = arch_hwcaps (vta.arch_host); diff --git a/tests/arch_test.c b/tests/arch_test.c index 4dbb8ca109..84b1f13079 100644 --- a/tests/arch_test.c +++ b/tests/arch_test.c @@ -34,6 +34,7 @@ char* all_archs[] = { "mips32", "mips64", "nanomips", + "riscv64", NULL }; @@ -79,6 +80,10 @@ static Bool go(char* arch) #elif defined(VGP_nanomips_linux) if ( 0 == strcmp( arch, "nanomips" ) ) return True; + +#elif defined(VGP_riscv64_linux) + if ( 0 == strcmp( arch, "riscv64" ) ) return True; + #else # error Unknown platform #endif // VGP_* diff --git a/tests/platform_test b/tests/platform_test index c23a4f6453..9762d0c09b 100644 --- a/tests/platform_test +++ b/tests/platform_test @@ -14,6 +14,7 @@ all_platforms= all_platforms="$all_platforms x86-linux amd64-linux ppc32-linux ppc64-linux" all_platforms="$all_platforms arm-linux arm64-linux" all_platforms="$all_platforms s390x-linux mips32-linux mips64-linux" +all_platforms="$all_platforms riscv64-linux" all_platforms="$all_platforms x86-darwin amd64-darwin" all_platforms="$all_platforms x86-solaris amd64-solaris" all_platforms="$all_platforms x86-freebsd amd64-freebsd" |
From: Mark W. <ma...@so...> - 2025-02-25 16:52:37
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=33833e37bf519c7532e69954f2b46f23a5215cab commit 33833e37bf519c7532e69954f2b46f23a5215cab Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:43 2023 +0000 riscv64: Add initial support: VEX modifications The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> https://bugs.kde.org/show_bug.cgi?id=493507 Diff: --- VEX/auxprogs/genoffsets.c | 69 +++++++++++++++++++++++++++++ VEX/priv/host_generic_regs.h | 1 + VEX/priv/main_main.c | 100 ++++++++++++++++++++++++++++++++++++++----- VEX/priv/main_util.h | 11 +++++ VEX/pub/libvex.h | 11 +++++ VEX/pub/libvex_basictypes.h | 5 ++- VEX/pub/libvex_ir.h | 3 +- VEX/useful/test_main.c | 13 +++++- 8 files changed, 200 insertions(+), 13 deletions(-) diff --git a/VEX/auxprogs/genoffsets.c b/VEX/auxprogs/genoffsets.c index 6b70cd087d..48c9723dc6 100644 --- a/VEX/auxprogs/genoffsets.c +++ b/VEX/auxprogs/genoffsets.c @@ -53,6 +53,7 @@ #include "../pub/libvex_guest_s390x.h" #include "../pub/libvex_guest_mips32.h" #include "../pub/libvex_guest_mips64.h" +#include "../pub/libvex_guest_riscv64.h" #define VG_STRINGIFZ(__str) #__str #define VG_STRINGIFY(__str) VG_STRINGIFZ(__str) @@ -265,6 +266,74 @@ void foo ( void ) GENOFFSET(MIPS64,mips64,PC); GENOFFSET(MIPS64,mips64,HI); GENOFFSET(MIPS64,mips64,LO); + + // riscv64 + GENOFFSET(RISCV64,riscv64,x0); + GENOFFSET(RISCV64,riscv64,x1); + GENOFFSET(RISCV64,riscv64,x2); + GENOFFSET(RISCV64,riscv64,x3); + GENOFFSET(RISCV64,riscv64,x4); + GENOFFSET(RISCV64,riscv64,x5); + GENOFFSET(RISCV64,riscv64,x6); + GENOFFSET(RISCV64,riscv64,x7); + GENOFFSET(RISCV64,riscv64,x8); + GENOFFSET(RISCV64,riscv64,x9); + GENOFFSET(RISCV64,riscv64,x10); + GENOFFSET(RISCV64,riscv64,x11); + GENOFFSET(RISCV64,riscv64,x12); + GENOFFSET(RISCV64,riscv64,x13); + GENOFFSET(RISCV64,riscv64,x14); + GENOFFSET(RISCV64,riscv64,x15); + GENOFFSET(RISCV64,riscv64,x16); + GENOFFSET(RISCV64,riscv64,x17); + GENOFFSET(RISCV64,riscv64,x18); + GENOFFSET(RISCV64,riscv64,x19); + GENOFFSET(RISCV64,riscv64,x20); + GENOFFSET(RISCV64,riscv64,x21); + GENOFFSET(RISCV64,riscv64,x22); + GENOFFSET(RISCV64,riscv64,x23); + GENOFFSET(RISCV64,riscv64,x24); + GENOFFSET(RISCV64,riscv64,x25); + GENOFFSET(RISCV64,riscv64,x26); + GENOFFSET(RISCV64,riscv64,x27); + GENOFFSET(RISCV64,riscv64,x28); + GENOFFSET(RISCV64,riscv64,x29); + GENOFFSET(RISCV64,riscv64,x30); + GENOFFSET(RISCV64,riscv64,x31); + GENOFFSET(RISCV64,riscv64,pc); + GENOFFSET(RISCV64,riscv64,f0); + GENOFFSET(RISCV64,riscv64,f1); + GENOFFSET(RISCV64,riscv64,f2); + GENOFFSET(RISCV64,riscv64,f3); + GENOFFSET(RISCV64,riscv64,f4); + GENOFFSET(RISCV64,riscv64,f5); + GENOFFSET(RISCV64,riscv64,f6); + GENOFFSET(RISCV64,riscv64,f7); + GENOFFSET(RISCV64,riscv64,f8); + GENOFFSET(RISCV64,riscv64,f9); + GENOFFSET(RISCV64,riscv64,f10); + GENOFFSET(RISCV64,riscv64,f11); + GENOFFSET(RISCV64,riscv64,f12); + GENOFFSET(RISCV64,riscv64,f13); + GENOFFSET(RISCV64,riscv64,f14); + GENOFFSET(RISCV64,riscv64,f15); + GENOFFSET(RISCV64,riscv64,f16); + GENOFFSET(RISCV64,riscv64,f17); + GENOFFSET(RISCV64,riscv64,f18); + GENOFFSET(RISCV64,riscv64,f19); + GENOFFSET(RISCV64,riscv64,f20); + GENOFFSET(RISCV64,riscv64,f21); + GENOFFSET(RISCV64,riscv64,f22); + GENOFFSET(RISCV64,riscv64,f23); + GENOFFSET(RISCV64,riscv64,f24); + GENOFFSET(RISCV64,riscv64,f25); + GENOFFSET(RISCV64,riscv64,f26); + GENOFFSET(RISCV64,riscv64,f27); + GENOFFSET(RISCV64,riscv64,f28); + GENOFFSET(RISCV64,riscv64,f29); + GENOFFSET(RISCV64,riscv64,f30); + GENOFFSET(RISCV64,riscv64,f31); + GENOFFSET(RISCV64,riscv64,fcsr); } /*--------------------------------------------------------------------*/ diff --git a/VEX/priv/host_generic_regs.h b/VEX/priv/host_generic_regs.h index 2387f49c6e..2b369f2ebd 100644 --- a/VEX/priv/host_generic_regs.h +++ b/VEX/priv/host_generic_regs.h @@ -36,6 +36,7 @@ #include "libvex_basictypes.h" +#include "main_util.h" /*---------------------------------------------------------*/ /*--- Representing HOST REGISTERS ---*/ diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index e6c788d0cb..91bb3bbbff 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -43,6 +43,7 @@ #include "libvex_guest_s390x.h" #include "libvex_guest_mips32.h" #include "libvex_guest_mips64.h" +#include "libvex_guest_riscv64.h" #include "main_globals.h" #include "main_util.h" @@ -57,6 +58,7 @@ #include "host_s390_defs.h" #include "host_mips_defs.h" #include "host_nanomips_defs.h" +#include "host_riscv64_defs.h" #include "guest_generic_bb_to_IR.h" #include "guest_x86_defs.h" @@ -67,6 +69,7 @@ #include "guest_s390_defs.h" #include "guest_mips_defs.h" #include "guest_nanomips_defs.h" +#include "guest_riscv64_defs.h" #include "host_generic_simd128.h" @@ -163,6 +166,14 @@ #define NANOMIPSST(f) vassert(0) #endif +#if defined(VGA_riscv64) || defined(VEXMULTIARCH) +#define RISCV64FN(f) f +#define RISCV64ST(f) f +#else +#define RISCV64FN(f) NULL +#define RISCV64ST(f) vassert(0) +#endif + /* This file contains the top level interface to the library. */ /* --------- fwds ... --------- */ @@ -541,6 +552,23 @@ IRSB* LibVEX_FrontEnd ( /*MOD*/ VexTranslateArgs* vta, vassert(sizeof( ((VexGuestMIPS32State*)0)->guest_NRADDR ) == 4); break; + case VexArchRISCV64: + preciseMemExnsFn + = RISCV64FN(guest_riscv64_state_requires_precise_mem_exns); + disInstrFn = RISCV64FN(disInstr_RISCV64); + specHelper = RISCV64FN(guest_riscv64_spechelper); + guest_layout = RISCV64FN(&riscv64guest_layout); + offB_CMSTART = offsetof(VexGuestRISCV64State,guest_CMSTART); + offB_CMLEN = offsetof(VexGuestRISCV64State,guest_CMLEN); + offB_GUEST_IP = offsetof(VexGuestRISCV64State,guest_pc); + szB_GUEST_IP = sizeof( ((VexGuestRISCV64State*)0)->guest_pc ); + vassert(vta->archinfo_guest.endness == VexEndnessLE); + vassert(0 == sizeof(VexGuestRISCV64State) % LibVEX_GUEST_STATE_ALIGN); + vassert(sizeof( ((VexGuestRISCV64State*)0)->guest_CMSTART ) == 8); + vassert(sizeof( ((VexGuestRISCV64State*)0)->guest_CMLEN ) == 8); + vassert(sizeof( ((VexGuestRISCV64State*)0)->guest_NRADDR ) == 8); + break; + default: vpanic("LibVEX_Translate: unsupported guest insn set"); } @@ -878,6 +906,14 @@ static void libvex_BackEnd ( const VexTranslateArgs *vta, offB_HOST_EvC_FAILADDR = offsetof(VexGuestMIPS32State,host_EvC_FAILADDR); break; + case VexArchRISCV64: + preciseMemExnsFn + = RISCV64FN(guest_riscv64_state_requires_precise_mem_exns); + guest_sizeB = sizeof(VexGuestRISCV64State); + offB_HOST_EvC_COUNTER = offsetof(VexGuestRISCV64State,host_EvC_COUNTER); + offB_HOST_EvC_FAILADDR = offsetof(VexGuestRISCV64State,host_EvC_FAILADDR); + break; + default: vpanic("LibVEX_Codegen: unsupported guest insn set"); } @@ -1052,6 +1088,22 @@ static void libvex_BackEnd ( const VexTranslateArgs *vta, || vta->archinfo_host.endness == VexEndnessBE); break; + case VexArchRISCV64: + mode64 = True; + rRegUniv = RISCV64FN(getRRegUniverse_RISCV64()); + getRegUsage + = CAST_TO_TYPEOF(getRegUsage) RISCV64FN(getRegUsage_RISCV64Instr); + mapRegs = CAST_TO_TYPEOF(mapRegs) RISCV64FN(mapRegs_RISCV64Instr); + genSpill = CAST_TO_TYPEOF(genSpill) RISCV64FN(genSpill_RISCV64); + genReload = CAST_TO_TYPEOF(genReload) RISCV64FN(genReload_RISCV64); + genMove = CAST_TO_TYPEOF(genMove) RISCV64FN(genMove_RISCV64); + ppInstr = CAST_TO_TYPEOF(ppInstr) RISCV64FN(ppRISCV64Instr); + ppReg = CAST_TO_TYPEOF(ppReg) RISCV64FN(ppHRegRISCV64); + iselSB = RISCV64FN(iselSB_RISCV64); + emit = CAST_TO_TYPEOF(emit) RISCV64FN(emit_RISCV64Instr); + vassert(vta->archinfo_host.endness == VexEndnessLE); + break; + default: vpanic("LibVEX_Translate: unsupported host insn set"); } @@ -1297,6 +1349,11 @@ VexInvalRange LibVEX_Chain ( VexArch arch_host, place_to_chain, disp_cp_chain_me_EXPECTED, place_to_jump_to)); + case VexArchRISCV64: + RISCV64ST(return chainXDirect_RISCV64(endness_host, + place_to_chain, + disp_cp_chain_me_EXPECTED, + place_to_jump_to)); default: vassert(0); } @@ -1359,6 +1416,11 @@ VexInvalRange LibVEX_UnChain ( VexArch arch_host, place_to_unchain, place_to_jump_to_EXPECTED, disp_cp_chain_me)); + case VexArchRISCV64: + RISCV64ST(return unchainXDirect_RISCV64(endness_host, + place_to_unchain, + place_to_jump_to_EXPECTED, + disp_cp_chain_me)); default: vassert(0); } @@ -1387,8 +1449,10 @@ Int LibVEX_evCheckSzB ( VexArch arch_host ) MIPS32ST(cached = evCheckSzB_MIPS()); break; case VexArchMIPS64: MIPS64ST(cached = evCheckSzB_MIPS()); break; - case VexArchNANOMIPS: + case VexArchNANOMIPS: NANOMIPSST(cached = evCheckSzB_NANOMIPS()); break; + case VexArchRISCV64: + RISCV64ST(cached = evCheckSzB_RISCV64()); break; default: vassert(0); } @@ -1432,6 +1496,9 @@ VexInvalRange LibVEX_PatchProfInc ( VexArch arch_host, case VexArchNANOMIPS: NANOMIPSST(return patchProfInc_NANOMIPS(endness_host, place_to_patch, location_of_counter)); + case VexArchRISCV64: + RISCV64ST(return patchProfInc_RISCV64(endness_host, place_to_patch, + location_of_counter)); default: vassert(0); } @@ -1515,6 +1582,7 @@ const HChar* LibVEX_ppVexArch ( VexArch arch ) case VexArchMIPS32: return "MIPS32"; case VexArchMIPS64: return "MIPS64"; case VexArchNANOMIPS: return "NANOMIPS"; + case VexArchRISCV64: return "RISCV64"; default: return "VexArch???"; } } @@ -1586,6 +1654,7 @@ static IRType arch_word_size (VexArch arch) { case VexArchMIPS64: case VexArchPPC64: case VexArchS390X: + case VexArchRISCV64: return Ity_I64; default: @@ -1929,6 +1998,11 @@ static const HChar* show_hwcaps_mips64 ( UInt hwcaps ) return "Unsupported baseline"; } +static const HChar* show_hwcaps_riscv64 ( UInt hwcaps ) +{ + return "riscv64"; +} + #undef NUM_HWCAPS /* Thie function must not return NULL. */ @@ -1936,15 +2010,16 @@ static const HChar* show_hwcaps_mips64 ( UInt hwcaps ) static const HChar* show_hwcaps ( VexArch arch, UInt hwcaps ) { switch (arch) { - case VexArchX86: return show_hwcaps_x86(hwcaps); - case VexArchAMD64: return show_hwcaps_amd64(hwcaps); - case VexArchPPC32: return show_hwcaps_ppc32(hwcaps); - case VexArchPPC64: return show_hwcaps_ppc64(hwcaps); - case VexArchARM: return show_hwcaps_arm(hwcaps); - case VexArchARM64: return show_hwcaps_arm64(hwcaps); - case VexArchS390X: return show_hwcaps_s390x(hwcaps); - case VexArchMIPS32: return show_hwcaps_mips32(hwcaps); - case VexArchMIPS64: return show_hwcaps_mips64(hwcaps); + case VexArchX86: return show_hwcaps_x86(hwcaps); + case VexArchAMD64: return show_hwcaps_amd64(hwcaps); + case VexArchPPC32: return show_hwcaps_ppc32(hwcaps); + case VexArchPPC64: return show_hwcaps_ppc64(hwcaps); + case VexArchARM: return show_hwcaps_arm(hwcaps); + case VexArchARM64: return show_hwcaps_arm64(hwcaps); + case VexArchS390X: return show_hwcaps_s390x(hwcaps); + case VexArchMIPS32: return show_hwcaps_mips32(hwcaps); + case VexArchMIPS64: return show_hwcaps_mips64(hwcaps); + case VexArchRISCV64: return show_hwcaps_riscv64(hwcaps); default: return NULL; } } @@ -2207,6 +2282,11 @@ static void check_hwcaps ( VexArch arch, UInt hwcaps ) return; invalid_hwcaps(arch, hwcaps, "Unsupported baseline\n"); + case VexArchRISCV64: + if (hwcaps == 0) + return; + invalid_hwcaps(arch, hwcaps, "Cannot handle capabilities\n"); + default: vpanic("unknown architecture"); } diff --git a/VEX/priv/main_util.h b/VEX/priv/main_util.h index 2fa26b062d..7fd304dd14 100644 --- a/VEX/priv/main_util.h +++ b/VEX/priv/main_util.h @@ -100,6 +100,17 @@ extern SizeT vex_strlen ( const HChar* str ); extern void vex_bzero ( void* s, SizeT n ); +/* Math ops */ + +/* Sign extend an N-bit value up to 64 bits, by copying bit N-1 into all higher + positions. */ +static inline ULong vex_sx_to_64( ULong x, UInt n ) +{ + vassert(n >= 1 && n < 64); + return (ULong)((Long)(x << (64 - n)) >> (64 - n)); +} + + /* Storage management: clear the area, and allocate from it. */ /* By default allocation occurs in the temporary area. However, it is diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 1681077343..d99be23a02 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -60,6 +60,7 @@ typedef VexArchMIPS32, VexArchMIPS64, VexArchNANOMIPS, + VexArchRISCV64, } VexArch; @@ -1033,6 +1034,16 @@ extern void LibVEX_InitIRI ( const IRICB * ); ~~~~~ r21 is GSP. + riscv64 + ~~~~~~~ + On entry, x8/s0 should point to the guest state + 2048. RISC-V has + load/store instructions with immediate (offset from the base + register) in range -2048 to 2047. The adjustment of 2048 allows + LibVEX to effectively use the full range. When translating + riscv64->riscv64, only a single instruction is then needed to + read/write values in the guest state (primary + 2x shadow state + areas) and most of the spill area. + ALL GUEST ARCHITECTURES ~~~~~~~~~~~~~~~~~~~~~~~ The guest state must contain two pseudo-registers, guest_CMSTART diff --git a/VEX/pub/libvex_basictypes.h b/VEX/pub/libvex_basictypes.h index e3f1485d50..6c48b227c0 100644 --- a/VEX/pub/libvex_basictypes.h +++ b/VEX/pub/libvex_basictypes.h @@ -153,7 +153,6 @@ typedef unsigned long HWord; #undef VEX_HOST_WORDSIZE #undef VEX_REGPARM -/* The following 4 work OK for Linux. */ #if defined(__x86_64__) # define VEX_HOST_WORDSIZE 8 # define VEX_REGPARM(_n) /* */ @@ -198,6 +197,10 @@ typedef unsigned long HWord; # define VEX_HOST_WORDSIZE 4 # define VEX_REGPARM(_n) /* */ +#elif defined(__riscv) && (__riscv_xlen == 64) +# define VEX_HOST_WORDSIZE 8 +# define VEX_REGPARM(_n) /* */ + #else # error "Vex: Fatal: Can't establish the host architecture" #endif diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 2d09e37cbc..80ef8f27a4 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -2089,7 +2089,8 @@ typedef Irrm_PREPARE_SHORTER = 5, // Round to prepare for shorter // precision Irrm_AWAY_FROM_ZERO = 6, // Round to away from 0 - Irrm_NEAREST_TIE_TOWARD_0 = 7 // Round to nearest, ties towards 0 + Irrm_NEAREST_TIE_TOWARD_0 = 7, // Round to nearest, ties towards 0 + Irrm_INVALID = 8 // Invalid mode } IRRoundingMode; diff --git a/VEX/useful/test_main.c b/VEX/useful/test_main.c index cfed7a598d..85168e7043 100644 --- a/VEX/useful/test_main.c +++ b/VEX/useful/test_main.c @@ -101,7 +101,8 @@ int main ( int argc, char** argv ) VexTranslateResult tres; VexControl vcon; VexGuestExtents vge; - VexArchInfo vai_x86, vai_amd64, vai_ppc32, vai_arm, vai_mips32, vai_mips64; + VexArchInfo vai_x86, vai_amd64, vai_ppc32, vai_arm, vai_mips32, vai_mips64, + vai_riscv64; VexAbiInfo vbi; VexTranslateArgs vta; @@ -190,6 +191,10 @@ int main ( int argc, char** argv ) LibVEX_default_VexArchInfo(&vai_mips64); vai_mips64.endness = VexEndnessLE; + LibVEX_default_VexArchInfo(&vai_riscv64); + vai_riscv64.hwcaps = 0; + vai_riscv64.endness = VexEndnessLE; + LibVEX_default_VexAbiInfo(&vbi); vbi.guest_stack_redzone_size = 128; @@ -245,6 +250,12 @@ int main ( int argc, char** argv ) vta.guest_bytes = &origbuf[18 +1]; vta.guest_bytes_addr = (Addr) &origbuf[18 +1]; #endif +#if 0 /* riscv64 -> riscv64 */ + vta.arch_guest = VexArchRISCV64; + vta.archinfo_guest = vai_riscv64; + vta.arch_host = VexArchRISCV64; + vta.archinfo_host = vai_riscv64; +#endif #if 1 /* no instrumentation */ vta.instrument1 = NULL; |
From: Mark W. <ma...@so...> - 2025-02-25 16:52:34
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=32fc9cc751809c90deac9d40f1c755691de6ce12 commit 32fc9cc751809c90deac9d40f1c755691de6ce12 Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:42 2023 +0000 riscv64: Add initial support: Valgrind modifications The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> https://bugs.kde.org/show_bug.cgi?id=493507 Diff: --- .gitignore | 30 ++ Makefile.all.am | 6 + Makefile.am | 1 + Makefile.tool.am | 11 + Makefile.vex.am | 14 +- cachegrind/cg_arch.c | 7 + cachegrind/cg_branchpred.c | 2 +- configure.ac | 28 +- coregrind/Makefile.am | 15 +- coregrind/launcher-linux.c | 23 +- coregrind/m_aspacemgr/aspacemgr-common.c | 11 +- coregrind/m_cache.c | 3 +- coregrind/m_coredump/coredump-elf.c | 70 +++- coregrind/m_debuginfo/d3basics.c | 3 + coregrind/m_debuginfo/debuginfo.c | 36 +- coregrind/m_debuginfo/priv_storage.h | 13 + coregrind/m_debuginfo/readdwarf.c | 42 ++- coregrind/m_debuginfo/readelf.c | 4 +- coregrind/m_debuginfo/storage.c | 5 + coregrind/m_debuglog.c | 28 ++ coregrind/m_gdbserver/target.c | 2 + coregrind/m_gdbserver/valgrind_low.h | 1 + coregrind/m_initimg/initimg-linux.c | 35 +- coregrind/m_libcassert.c | 19 ++ coregrind/m_libcfile.c | 56 ++-- coregrind/m_libcproc.c | 27 +- coregrind/m_machine.c | 60 +++- coregrind/m_main.c | 32 ++ coregrind/m_options.c | 3 +- coregrind/m_redir.c | 15 + coregrind/m_scheduler/scheduler.c | 9 + coregrind/m_signals.c | 67 ++-- coregrind/m_stacktrace.c | 95 ++++++ coregrind/m_syscall.c | 39 +++ coregrind/m_syswrap/priv_syswrap-linux.h | 7 + coregrind/m_syswrap/priv_types_n_macros.h | 2 +- coregrind/m_syswrap/syswrap-generic.c | 4 +- coregrind/m_syswrap/syswrap-linux.c | 32 +- coregrind/m_syswrap/syswrap-main.c | 74 +++++ coregrind/m_trampoline.S | 76 +++++ coregrind/m_translate.c | 4 + coregrind/pub_core_basics.h | 10 +- coregrind/pub_core_debuginfo.h | 4 + coregrind/pub_core_machine.h | 9 + coregrind/pub_core_mallocfree.h | 1 + coregrind/pub_core_syscall.h | 1 + coregrind/pub_core_trampoline.h | 6 + coregrind/pub_core_transtab.h | 3 +- coregrind/pub_core_transtab_asm.h | 11 +- coregrind/vgdb-invoker-ptrace.c | 25 +- docs/Makefile.am | 1 + docs/xml/dist-docs.xml | 10 + drd/drd_bitmap.h | 2 +- drd/drd_load_store.c | 2 + include/Makefile.am | 3 + include/pub_tool_basics.h | 6 +- include/pub_tool_guest.h | 3 + include/pub_tool_machine.h | 6 + include/pub_tool_redir.h | 2 + include/pub_tool_vkiscnums_asm.h | 4 + include/valgrind.h.in | 535 ++++++++++++++++++++++++++++++ include/vki/vki-linux.h | 4 + memcheck/mc_machine.c | 105 ++++++ 63 files changed, 1666 insertions(+), 98 deletions(-) diff --git a/.gitignore b/.gitignore index c5a2b0592c..de2306df78 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ /auxprogs/getoff-mips32-linux /auxprogs/getoff-mips64-linux /auxprogs/getoff-nanomips-linux +/auxprogs/getoff-riscv64-linux /auxprogs/getoff-amd64-solaris /auxprogs/getoff-x86-solaris /auxprogs/getoff-*-freebsd @@ -1132,6 +1133,18 @@ /memcheck/tests/arm64-linux/Makefile.in /memcheck/tests/arm64-linux/scalar +# /memcheck/tests/riscv64-linux/ +/memcheck/tests/riscv64-linux/*.stderr.diff +/memcheck/tests/riscv64-linux/*.stderr.out +/memcheck/tests/riscv64-linux/*.stdout.diff +/memcheck/tests/riscv64-linux/*.stdout.out +/memcheck/tests/riscv64-linux/.deps +/memcheck/tests/riscv64-linux/Makefile +/memcheck/tests/riscv64-linux/Makefile.in +/memcheck/tests/riscv64-linux/context_float +/memcheck/tests/riscv64-linux/context_integer +/memcheck/tests/riscv64-linux/scalar + # /memcheck/tests/common/ /memcheck/tests/common/Makefile /memcheck/tests/common/Makefile.in @@ -2201,6 +2214,23 @@ /none/tests/s390x/vec2 /none/tests/s390x/vec2_float +# /none/tests/riscv64/ +/none/tests/riscv64/*.stderr.diff +/none/tests/riscv64/*.stderr.out +/none/tests/riscv64/*.stdout.diff +/none/tests/riscv64/*.stdout.out +/none/tests/riscv64/.deps +/none/tests/riscv64/Makefile +/none/tests/riscv64/Makefile.in +/none/tests/riscv64/allexec +/none/tests/riscv64/atomic +/none/tests/riscv64/compressed +/none/tests/riscv64/csr +/none/tests/riscv64/float32 +/none/tests/riscv64/float64 +/none/tests/riscv64/integer +/none/tests/riscv64/muldiv + # /none/tests/scripts/ /none/tests/scripts/*.dSYM /none/tests/scripts/*.so diff --git a/Makefile.all.am b/Makefile.all.am index e221198d6c..d4f6b3fb79 100755 --- a/Makefile.all.am +++ b/Makefile.all.am @@ -292,6 +292,11 @@ AM_CFLAGS_PSO_MIPS64_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) \ $(AM_CFLAGS_PSO_BASE) AM_CCASFLAGS_MIPS64_LINUX = @FLAG_M64@ -g +AM_FLAG_M3264_RISCV64_LINUX = @FLAG_M64@ +AM_CFLAGS_RISCV64_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) +AM_CFLAGS_PSO_RISCV64_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE) +AM_CCASFLAGS_RISCV64_LINUX = @FLAG_M64@ -g + AM_FLAG_M3264_X86_SOLARIS = @FLAG_M32@ AM_CFLAGS_X86_SOLARIS = @FLAG_M32@ @PREFERRED_STACK_BOUNDARY_2@ \ $(AM_CFLAGS_BASE) -fomit-frame-pointer @SOLARIS_UNDEF_LARGESOURCE@ @@ -353,6 +358,7 @@ PRELOAD_LDFLAGS_S390X_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ PRELOAD_LDFLAGS_MIPS32_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@ PRELOAD_LDFLAGS_NANOMIPS_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@ PRELOAD_LDFLAGS_MIPS64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ +PRELOAD_LDFLAGS_RISCV64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ PRELOAD_LDFLAGS_X86_SOLARIS = $(PRELOAD_LDFLAGS_COMMON_SOLARIS) @FLAG_M32@ PRELOAD_LDFLAGS_AMD64_SOLARIS = $(PRELOAD_LDFLAGS_COMMON_SOLARIS) @FLAG_M64@ diff --git a/Makefile.am b/Makefile.am index d745e26bf4..db8cfa382c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,6 +118,7 @@ EXTRA_DIST = \ README.android_emulator \ README.mips \ README.aarch64 \ + README.riscv64 \ README.solaris \ README.freebsd \ NEWS.old \ diff --git a/Makefile.tool.am b/Makefile.tool.am index c779596e71..7f18d25476 100644 --- a/Makefile.tool.am +++ b/Makefile.tool.am @@ -110,6 +110,9 @@ TOOL_LDFLAGS_MIPS64_LINUX = \ -static -nodefaultlibs -nostartfiles -u __start @FLAG_NO_BUILD_ID@ \ @FLAG_M64@ +TOOL_LDFLAGS_RISCV64_LINUX = \ + $(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M64@ + TOOL_LDFLAGS_X86_SOLARIS = \ $(TOOL_LDFLAGS_COMMON_SOLARIS) @FLAG_M32@ @@ -181,6 +184,9 @@ LIBREPLACEMALLOC_MIPS32_LINUX = \ LIBREPLACEMALLOC_MIPS64_LINUX = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-mips64-linux.a +LIBREPLACEMALLOC_RISCV64_LINUX = \ + $(top_builddir)/coregrind/libreplacemalloc_toolpreload-riscv64-linux.a + LIBREPLACEMALLOC_X86_SOLARIS = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-solaris.a @@ -258,6 +264,11 @@ LIBREPLACEMALLOC_LDFLAGS_MIPS64_LINUX = \ $(LIBREPLACEMALLOC_MIPS64_LINUX) \ -Wl,--no-whole-archive +LIBREPLACEMALLOC_LDFLAGS_RISCV64_LINUX = \ + -Wl,--whole-archive \ + $(LIBREPLACEMALLOC_RISCV64_LINUX) \ + -Wl,--no-whole-archive + LIBREPLACEMALLOC_LDFLAGS_X86_SOLARIS = \ -Wl,--whole-archive \ $(LIBREPLACEMALLOC_X86_SOLARIS) \ diff --git a/Makefile.vex.am b/Makefile.vex.am index c1244a69d2..f75e9b4c69 100644 --- a/Makefile.vex.am +++ b/Makefile.vex.am @@ -26,6 +26,7 @@ pkginclude_HEADERS = \ pub/libvex_guest_s390x.h \ pub/libvex_guest_mips32.h \ pub/libvex_guest_mips64.h \ + pub/libvex_guest_riscv64.h \ pub/libvex_s390x_common.h \ pub/libvex_ir.h \ pub/libvex_trc_values.h \ @@ -49,6 +50,7 @@ noinst_HEADERS = \ priv/guest_mips_defs.h \ priv/mips_defs.h \ priv/guest_nanomips_defs.h \ + priv/guest_riscv64_defs.h \ priv/host_generic_regs.h \ priv/host_generic_simd64.h \ priv/host_generic_simd128.h \ @@ -65,7 +67,8 @@ noinst_HEADERS = \ priv/s390_defs.h \ priv/host_mips_defs.h \ priv/host_nanomips_defs.h \ - priv/common_nanomips_defs.h + priv/common_nanomips_defs.h \ + priv/host_riscv64_defs.h BUILT_SOURCES = pub/libvex_guest_offsets.h CLEANFILES = pub/libvex_guest_offsets.h @@ -94,7 +97,8 @@ pub/libvex_guest_offsets.h: auxprogs/genoffsets.c \ pub/libvex_guest_arm64.h \ pub/libvex_guest_s390x.h \ pub/libvex_guest_mips32.h \ - pub/libvex_guest_mips64.h + pub/libvex_guest_mips64.h \ + pub/libvex_guest_riscv64.h rm -f auxprogs/genoffsets.s $(mkdir_p) auxprogs pub $(CC) $(CFLAGS_FOR_GENOFFSETS) \ @@ -152,6 +156,8 @@ LIBVEX_SOURCES_COMMON = \ priv/guest_mips_toIR.c \ priv/guest_nanomips_helpers.c \ priv/guest_nanomips_toIR.c \ + priv/guest_riscv64_helpers.c \ + priv/guest_riscv64_toIR.c \ priv/host_generic_regs.c \ priv/host_generic_simd64.c \ priv/host_generic_simd128.c \ @@ -176,7 +182,9 @@ LIBVEX_SOURCES_COMMON = \ priv/host_mips_defs.c \ priv/host_nanomips_defs.c \ priv/host_mips_isel.c \ - priv/host_nanomips_isel.c + priv/host_nanomips_isel.c \ + priv/host_riscv64_defs.c \ + priv/host_riscv64_isel.c LIBVEXMULTIARCH_SOURCES = priv/multiarch_main_main.c diff --git a/cachegrind/cg_arch.c b/cachegrind/cg_arch.c index 68314c9dbe..be2973405a 100644 --- a/cachegrind/cg_arch.c +++ b/cachegrind/cg_arch.c @@ -484,6 +484,13 @@ configure_caches(cache_t *I1c, cache_t *D1c, cache_t *LLc, *D1c = (cache_t) { 65536, 2, 64 }; *LLc = (cache_t) { 262144, 8, 64 }; +#elif defined(VGA_riscv64) + + // Default cache configuration is SiFive FU740-C000 (HiFive Unmatched) + *I1c = (cache_t) { 32768, 4, 64 }; + *D1c = (cache_t) { 32768, 8, 64 }; + *LLc = (cache_t) { 2097152, 16, 64 }; + #else #error "Unknown arch" diff --git a/cachegrind/cg_branchpred.c b/cachegrind/cg_branchpred.c index 927b7bf21c..f7a261c6fe 100644 --- a/cachegrind/cg_branchpred.c +++ b/cachegrind/cg_branchpred.c @@ -48,7 +48,7 @@ # define N_IADDR_LO_ZERO_BITS 2 #elif defined(VGA_x86) || defined(VGA_amd64) # define N_IADDR_LO_ZERO_BITS 0 -#elif defined(VGA_s390x) || defined(VGA_arm) +#elif defined(VGA_s390x) || defined(VGA_arm) || defined(VGA_riscv64) # define N_IADDR_LO_ZERO_BITS 1 #else # error "Unsupported architecture" diff --git a/configure.ac b/configure.ac index 9dec9f3b00..e6ae0501bd 100755 --- a/configure.ac +++ b/configure.ac @@ -302,6 +302,11 @@ case "${host_cpu}" in ARCH_MAX="nanomips" ;; + riscv64) + AC_MSG_RESULT([ok (${host_cpu})]) + ARCH_MAX="riscv64" + ;; + *) AC_MSG_RESULT([no (${host_cpu})]) AC_MSG_ERROR([Unsupported host architecture. Sorry]) @@ -874,6 +879,17 @@ case "$ARCH_MAX-$VGCONF_OS" in valt_load_address_sec_inner="0xUNSET" AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})]) ;; + riscv64-linux) + VGCONF_ARCH_PRI="riscv64" + VGCONF_ARCH_SEC="" + VGCONF_PLATFORM_PRI_CAPS="RISCV64_LINUX" + VGCONF_PLATFORM_SEC_CAPS="" + valt_load_address_pri_norml="0x58000000" + valt_load_address_pri_inner="0x38000000" + valt_load_address_sec_norml="0xUNSET" + valt_load_address_sec_inner="0xUNSET" + AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})]) + ;; x86-solaris) VGCONF_ARCH_PRI="x86" VGCONF_ARCH_SEC="" @@ -967,6 +983,8 @@ AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_MIPS64, test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX ) AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_NANOMIPS, test x$VGCONF_PLATFORM_PRI_CAPS = xNANOMIPS_LINUX ) +AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_RISCV64, + test x$VGCONF_PLATFORM_PRI_CAPS = xRISCV64_LINUX ) # Set up VGCONF_PLATFORMS_INCLUDE_<platform>. Either one or two of these # become defined. @@ -997,6 +1015,8 @@ AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_MIPS64_LINUX, test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX) AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_NANOMIPS_LINUX, test x$VGCONF_PLATFORM_PRI_CAPS = xNANOMIPS_LINUX) +AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_RISCV64_LINUX, + test x$VGCONF_PLATFORM_PRI_CAPS = xRISCV64_LINUX) AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_FREEBSD, test x$VGCONF_PLATFORM_PRI_CAPS = xX86_FREEBSD \ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_FREEBSD) @@ -1030,7 +1050,8 @@ AM_CONDITIONAL(VGCONF_OS_IS_LINUX, -o x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \ - -o x$VGCONF_PLATFORM_PRI_CAPS = xNANOMIPS_LINUX) + -o x$VGCONF_PLATFORM_PRI_CAPS = xNANOMIPS_LINUX \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xRISCV64_LINUX) AM_CONDITIONAL(VGCONF_OS_IS_FREEBSD, test x$VGCONF_PLATFORM_PRI_CAPS = xX86_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_FREEBSD \ @@ -5049,7 +5070,8 @@ elif test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xARM64_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xARM64_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \ - -o x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX ; then + -o x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xRISCV64_LINUX ; then mflag_primary=$FLAG_M64 elif test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN ; then mflag_primary="$FLAG_M32 -arch i386" @@ -5657,6 +5679,7 @@ AC_CONFIG_FILES([ memcheck/tests/amd64-linux/Makefile memcheck/tests/arm64-linux/Makefile memcheck/tests/x86-linux/Makefile + memcheck/tests/riscv64-linux/Makefile memcheck/tests/amd64-solaris/Makefile memcheck/tests/x86-solaris/Makefile memcheck/tests/amd64-freebsd/Makefile @@ -5702,6 +5725,7 @@ AC_CONFIG_FILES([ none/tests/mips32/Makefile none/tests/mips64/Makefile none/tests/nanomips/Makefile + none/tests/riscv64/Makefile none/tests/linux/Makefile none/tests/darwin/Makefile none/tests/solaris/Makefile diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 5491fc6726..700751dea4 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -392,6 +392,7 @@ COREGRIND_SOURCES_COMMON = \ m_dispatch/dispatch-mips32-linux.S \ m_dispatch/dispatch-mips64-linux.S \ m_dispatch/dispatch-nanomips-linux.S \ + m_dispatch/dispatch-riscv64-linux.S \ m_dispatch/dispatch-x86-freebsd.S \ m_dispatch/dispatch-amd64-freebsd.S \ m_dispatch/dispatch-arm64-freebsd.S \ @@ -419,6 +420,7 @@ COREGRIND_SOURCES_COMMON = \ m_gdbserver/valgrind-low-mips32.c \ m_gdbserver/valgrind-low-mips64.c \ m_gdbserver/valgrind-low-nanomips.c \ + m_gdbserver/valgrind-low-riscv64.c \ m_gdbserver/version.c \ m_initimg/initimg-linux.c \ m_initimg/initimg-freebsd.c \ @@ -447,6 +449,7 @@ COREGRIND_SOURCES_COMMON = \ m_sigframe/sigframe-mips32-linux.c \ m_sigframe/sigframe-mips64-linux.c \ m_sigframe/sigframe-nanomips-linux.c \ + m_sigframe/sigframe-riscv64-linux.c \ m_sigframe/sigframe-x86-darwin.c \ m_sigframe/sigframe-amd64-darwin.c \ m_sigframe/sigframe-solaris.c \ @@ -461,6 +464,7 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syscall-mips32-linux.S \ m_syswrap/syscall-mips64-linux.S \ m_syswrap/syscall-nanomips-linux.S \ + m_syswrap/syscall-riscv64-linux.S \ m_syswrap/syscall-x86-freebsd.S \ m_syswrap/syscall-amd64-freebsd.S \ m_syswrap/syscall-arm64-freebsd.S \ @@ -488,6 +492,7 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syswrap-mips32-linux.c \ m_syswrap/syswrap-mips64-linux.c \ m_syswrap/syswrap-nanomips-linux.c \ + m_syswrap/syswrap-riscv64-linux.c \ m_syswrap/syswrap-x86-darwin.c \ m_syswrap/syswrap-amd64-darwin.c \ m_syswrap/syswrap-xen.c \ @@ -780,7 +785,15 @@ GDBSERVER_XML_FILES = \ m_gdbserver/mips64-linux-valgrind.xml \ m_gdbserver/mips64-fpu-valgrind-s1.xml \ m_gdbserver/mips64-fpu-valgrind-s2.xml \ - m_gdbserver/mips64-fpu.xml + m_gdbserver/mips64-fpu.xml \ + m_gdbserver/riscv64-cpu-valgrind-s1.xml \ + m_gdbserver/riscv64-cpu-valgrind-s2.xml \ + m_gdbserver/riscv64-cpu.xml \ + m_gdbserver/riscv64-linux.xml \ + m_gdbserver/riscv64-linux-valgrind.xml \ + m_gdbserver/riscv64-fpu-valgrind-s1.xml \ + m_gdbserver/riscv64-fpu-valgrind-s2.xml \ + m_gdbserver/riscv64-fpu.xml # so as to make sure these get copied into the install tree vglibdir = $(pkglibexecdir) diff --git a/coregrind/launcher-linux.c b/coregrind/launcher-linux.c index 715fdab818..20e624003a 100644 --- a/coregrind/launcher-linux.c +++ b/coregrind/launcher-linux.c @@ -51,16 +51,18 @@ #include <string.h> #include <unistd.h> +/* Provide own definitions for elf.h constants that might not be yet available + on some older systems. */ #ifndef EM_X86_64 -#define EM_X86_64 62 // elf.h doesn't define this on some older systems +#define EM_X86_64 62 #endif #ifndef EM_AARCH64 -#define EM_AARCH64 183 // ditto +#define EM_AARCH64 183 #endif #ifndef EM_PPC64 -#define EM_PPC64 21 // ditto +#define EM_PPC64 21 #endif #ifndef EM_NANOMIPS @@ -75,6 +77,10 @@ #define E_MIPS_ABI2 0x00000020 #endif +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif + /* Report fatal errors */ __attribute__((noreturn)) static void barf ( const char *format, ... ) @@ -316,6 +322,10 @@ static const char *select_platform(const char *clientname) (header.ehdr64.e_ident[EI_OSABI] == ELFOSABI_SYSV || header.ehdr64.e_ident[EI_OSABI] == ELFOSABI_LINUX)) { platform = "ppc64le-linux"; + } else if (header.ehdr64.e_machine == EM_RISCV && + (header.ehdr64.e_ident[EI_OSABI] == ELFOSABI_SYSV || + header.ehdr64.e_ident[EI_OSABI] == ELFOSABI_LINUX)) { + platform = "riscv64-linux"; } } else if (header.c[EI_DATA] == ELFDATA2MSB) { # if !defined(VGPV_arm_linux_android) \ @@ -404,8 +414,8 @@ int main(int argc, char** argv, char** envp) the executable (eg because it's a shell script). VG_PLATFORM is the default_platform. Its value is defined in coregrind/Makefile.am and typically it is the primary build target. Unless the primary build - target is not built is not built in which case VG_PLATFORM is the - secondary build target. */ + target is not built in which case VG_PLATFORM is the secondary build + target. */ # if defined(VGO_linux) if ((0==strcmp(VG_PLATFORM,"x86-linux")) || (0==strcmp(VG_PLATFORM,"amd64-linux")) || @@ -417,7 +427,8 @@ int main(int argc, char** argv, char** envp) (0==strcmp(VG_PLATFORM,"s390x-linux")) || (0==strcmp(VG_PLATFORM,"mips32-linux")) || (0==strcmp(VG_PLATFORM,"mips64-linux")) || - (0==strcmp(VG_PLATFORM,"nanomips-linux"))) + (0==strcmp(VG_PLATFORM,"nanomips-linux")) || + (0==strcmp(VG_PLATFORM,"riscv64-linux"))) default_platform = VG_PLATFORM; # elif defined(VGO_solaris) if ((0==strcmp(VG_PLATFORM,"x86-solaris")) || diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c index 68bc5b40c9..14864d96c3 100644 --- a/coregrind/m_aspacemgr/aspacemgr-common.c +++ b/coregrind/m_aspacemgr/aspacemgr-common.c @@ -157,7 +157,8 @@ SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot, # elif defined(VGP_amd64_linux) \ || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \ - || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) + || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags, fd, offset); # elif defined(VGP_x86_darwin) @@ -262,8 +263,9 @@ SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)( SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode ) { -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) - /* ARM64 wants to use __NR_openat rather than __NR_open. */ +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) + /* More recent Linux platforms have only __NR_openat and no __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) @@ -291,7 +293,8 @@ void ML_(am_close) ( Int fd ) Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz) { SysRes res; -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) diff --git a/coregrind/m_cache.c b/coregrind/m_cache.c index d12941cd68..4abd26f0b2 100644 --- a/coregrind/m_cache.c +++ b/coregrind/m_cache.c @@ -539,7 +539,8 @@ get_cache_info(VexArchInfo *vai) #elif defined(VGA_arm) || defined(VGA_ppc32) || \ defined(VGA_ppc64be) || defined(VGA_ppc64le) || \ defined(VGA_mips32) || defined(VGA_mips64) || \ - defined(VGA_arm64) || defined(VGA_nanomips) + defined(VGA_arm64) || defined(VGA_nanomips) || \ + defined(VGA_riscv64) static Bool get_cache_info(VexArchInfo *vai) { diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c index a4632d9e28..b57d26275b 100644 --- a/coregrind/m_coredump/coredump-elf.c +++ b/coregrind/m_coredump/coredump-elf.c @@ -277,7 +277,7 @@ static void fill_prstatus(const ThreadState *tst, prs->pr_sid = VG_(getpgrp)(); #endif -#if defined(VGP_s390x_linux) +#if defined(VGP_s390x_linux) || defined(VGP_riscv64_linux) /* prs->pr_reg has struct type. Need to take address. */ regs = (struct vki_user_regs_struct *)&(prs->pr_reg); #elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ @@ -489,6 +489,39 @@ static void fill_prstatus(const ThreadState *tst, regs[VKI_MIPS32_EF_CP0_STATUS] = arch->vex.guest_CP0_status; regs[VKI_MIPS32_EF_CP0_EPC] = arch->vex.guest_PC; # undef DO +#elif defined(VGP_riscv64_linux) + regs->pc = arch->vex.guest_pc; + regs->ra = arch->vex.guest_x1; + regs->sp = arch->vex.guest_x2; + regs->gp = arch->vex.guest_x3; + regs->tp = arch->vex.guest_x4; + regs->t0 = arch->vex.guest_x5; + regs->t1 = arch->vex.guest_x6; + regs->t2 = arch->vex.guest_x7; + regs->s0 = arch->vex.guest_x8; + regs->s1 = arch->vex.guest_x9; + regs->a0 = arch->vex.guest_x10; + regs->a1 = arch->vex.guest_x11; + regs->a2 = arch->vex.guest_x12; + regs->a3 = arch->vex.guest_x13; + regs->a4 = arch->vex.guest_x14; + regs->a5 = arch->vex.guest_x15; + regs->a6 = arch->vex.guest_x16; + regs->a7 = arch->vex.guest_x17; + regs->s2 = arch->vex.guest_x18; + regs->s3 = arch->vex.guest_x19; + regs->s4 = arch->vex.guest_x20; + regs->s5 = arch->vex.guest_x21; + regs->s6 = arch->vex.guest_x22; + regs->s7 = arch->vex.guest_x23; + regs->s8 = arch->vex.guest_x24; + regs->s9 = arch->vex.guest_x25; + regs->s10 = arch->vex.guest_x26; + regs->s11 = arch->vex.guest_x27; + regs->t3 = arch->vex.guest_x28; + regs->t4 = arch->vex.guest_x29; + regs->t5 = arch->vex.guest_x30; + regs->t6 = arch->vex.guest_x31; #elif defined(VGP_amd64_freebsd) regs->rflags = LibVEX_GuestAMD64_get_rflags( &arch->vex ); regs->rsp = arch->vex.guest_RSP; @@ -691,6 +724,41 @@ static void fill_fpu(const ThreadState *tst, vki_elf_fpregset_t *fpu) # undef DO #elif defined(VGP_nanomips_linux) +#elif defined(VGP_riscv64_linux) + fpu->d.f[0] = arch->vex.guest_f0; + fpu->d.f[1] = arch->vex.guest_f1; + fpu->d.f[2] = arch->vex.guest_f2; + fpu->d.f[3] = arch->vex.guest_f3; + fpu->d.f[4] = arch->vex.guest_f4; + fpu->d.f[5] = arch->vex.guest_f5; + fpu->d.f[6] = arch->vex.guest_f6; + fpu->d.f[7] = arch->vex.guest_f7; + fpu->d.f[8] = arch->vex.guest_f8; + fpu->d.f[9] = arch->vex.guest_f9; + fpu->d.f[10] = arch->vex.guest_f10; + fpu->d.f[11] = arch->vex.guest_f11; + fpu->d.f[12] = arch->vex.guest_f12; + fpu->d.f[13] = arch->vex.guest_f13; + fpu->d.f[14] = arch->vex.guest_f14; + fpu->d.f[15] = arch->vex.guest_f15; + fpu->d.f[16] = arch->vex.guest_f16; + fpu->d.f[17] = arch->vex.guest_f17; + fpu->d.f[18] = arch->vex.guest_f18; + fpu->d.f[19] = arch->vex.guest_f19; + fpu->d.f[20] = arch->vex.guest_f20; + fpu->d.f[21] = arch->vex.guest_f21; + fpu->d.f[22] = arch->vex.guest_f22; + fpu->d.f[23] = arch->vex.guest_f23; + fpu->d.f[24] = arch->vex.guest_f24; + fpu->d.f[25] = arch->vex.guest_f25; + fpu->d.f[26] = arch->vex.guest_f26; + fpu->d.f[27] = arch->vex.guest_f27; + fpu->d.f[28] = arch->vex.guest_f28; + fpu->d.f[29] = arch->vex.guest_f29; + fpu->d.f[30] = arch->vex.guest_f30; + fpu->d.f[31] = arch->vex.guest_f31; + fpu->d.fcsr = arch->vex.guest_fcsr; + #elif defined(VGP_x86_freebsd) #elif defined(VGP_amd64_freebsd) diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c index 564b832e63..80dec21a65 100644 --- a/coregrind/m_debuginfo/d3basics.c +++ b/coregrind/m_debuginfo/d3basics.c @@ -555,6 +555,9 @@ static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, const RegSummary* regs ) # elif defined(VGP_arm64_linux) || defined(VGP_arm64_freebsd) if (regno == 31) { *a = regs->sp; return True; } if (regno == 29) { *a = regs->fp; return True; } +# elif defined(VGP_riscv64_linux) + if (regno == 2) { *a = regs->sp; return True; } + if (regno == 8) { *a = regs->fp; return True; } # else # error "Unknown platform" # endif diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index 11ab473542..97d0f35c05 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -1277,7 +1277,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) is_rx_map = seg->hasR && seg->hasX; is_rw_map = seg->hasR && seg->hasW; # elif defined(VGA_amd64) || defined(VGA_ppc64be) || defined(VGA_ppc64le) \ - || defined(VGA_arm) || defined(VGA_arm64) + || defined(VGA_arm) || defined(VGA_arm64) || defined(VGA_riscv64) is_rx_map = seg->hasR && seg->hasX && !seg->hasW; is_rw_map = seg->hasR && seg->hasW && !seg->hasX; # elif defined(VGP_s390x_linux) @@ -3092,12 +3092,12 @@ UWord evalCfiExpr ( const XArray* exprs, Int ix, case Creg_IA_SP: return eec->uregs->sp; case Creg_IA_BP: return eec->uregs->fp; case Creg_MIPS_RA: return eec->uregs->ra; -# elif defined(VGA_ppc32) || defined(VGA_ppc64be) \ - || defined(VGA_ppc64le) # elif defined(VGP_arm64_linux) || defined(VGP_arm64_freebsd) case Creg_ARM64_SP: return eec->uregs->sp; case Creg_ARM64_X30: return eec->uregs->x30; case Creg_ARM64_X29: return eec->uregs->x29; +# elif defined(VGA_ppc32) || defined(VGA_ppc64be) \ + || defined(VGA_ppc64le) || defined(VGP_riscv64_linux) # else # error "Unsupported arch" # endif @@ -3378,7 +3378,13 @@ static Addr compute_cfa ( const D3UnwindRegs* uregs, case CFIC_ARM64_X29REL: cfa = cfsi_m->cfa_off + uregs->x29; break; - +# elif defined(VGP_riscv64_linux) + case CFIC_IA_SPREL: + cfa = cfsi_m->cfa_off + uregs->sp; + break; + case CFIC_IA_BPREL: + cfa = cfsi_m->cfa_off + uregs->fp; + break; # else # error "Unsupported arch" # endif @@ -3450,6 +3456,15 @@ Addr ML_(get_CFA) ( Addr ip, Addr sp, Addr fp, return compute_cfa(&uregs, min_accessible, max_accessible, ce->di, ce->cfsi_m); } +#elif defined(VGA_riscv64) + { D3UnwindRegs uregs; + uregs.pc = ip; + uregs.sp = sp; + uregs.fp = fp; + uregs.ra = 0; + return compute_cfa(&uregs, + min_accessible, max_accessible, ce->di, ce->cfsi_m); + } # else return 0; /* indicates failure */ @@ -3501,6 +3516,8 @@ void VG_(ppUnwindInfo) (Addr from, Addr to) For arm64, the unwound registers are: X29(FP) X30(LR) SP PC. For s390, the unwound registers are: R11(FP) R14(LR) R15(SP) F0..F7 PC. + + For riscv64, the unwound registers are: X2(SP) X8(FP) PC */ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere, Addr min_accessible, @@ -3526,6 +3543,8 @@ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere, ipHere = uregsHere->pc; # elif defined(VGP_arm64_freebsd) ipHere = uregsHere->pc; +# elif defined(VGP_riscv64_linux) + ipHere = uregsHere->pc; # else # error "Unknown arch" # endif @@ -3671,6 +3690,15 @@ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere, COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi_m->sp_how, cfsi_m->sp_off); COMPUTE(uregsPrev.x30, uregsHere->x30, cfsi_m->x30_how, cfsi_m->x30_off); COMPUTE(uregsPrev.x29, uregsHere->x29, cfsi_m->x29_how, cfsi_m->x29_off); +# elif defined(VGP_riscv64_linux) + /* Compute register values in the caller's frame. Notice that the previous + pc is equal to the previous ra and is calculated as such. The previous ra + is however set to 0 here as this helps to promptly fail cases where an + inner frame uses the CFIR_SAME rule for ra which is bogus. */ + COMPUTE(uregsPrev.pc, uregsHere->ra, cfsi_m->ra_how, cfsi_m->ra_off); + COMPUTE(uregsPrev.sp, uregsHere->sp, cfsi_m->sp_how, cfsi_m->sp_off); + COMPUTE(uregsPrev.fp, uregsHere->fp, cfsi_m->fp_how, cfsi_m->fp_off); + uregsPrev.ra = 0; # else # error "Unknown arch" # endif diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h index 441b379d2e..d8cba81c48 100644 --- a/coregrind/m_debuginfo/priv_storage.h +++ b/coregrind/m_debuginfo/priv_storage.h @@ -355,6 +355,19 @@ typedef } DiCfSI_m; #elif defined(VGA_mips32) || defined(VGA_mips64) || defined(VGA_nanomips) +typedef + struct { + UChar cfa_how; /* a CFIC_ value */ + UChar ra_how; /* a CFIR_ value */ + UChar sp_how; /* a CFIR_ value */ + UChar fp_how; /* a CFIR_ value */ + Int cfa_off; + Int ra_off; + Int sp_off; + Int fp_off; + } + DiCfSI_m; +#elif defined(VGA_riscv64) typedef struct { UChar cfa_how; /* a CFIC_ value */ diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 0686e8d078..b08720182e 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -2066,6 +2066,10 @@ void ML_(read_debuginfo_dwarf1) ( # define FP_REG 30 # define SP_REG 29 # define RA_REG_DEFAULT 31 +#elif defined(VGP_riscv64_linux) +# define FP_REG 8 +# define SP_REG 2 +# define RA_REG_DEFAULT 1 #else # error "Unknown platform" #endif @@ -2084,6 +2088,8 @@ void ML_(read_debuginfo_dwarf1) ( # define N_CFI_REGS 128 #elif defined(VGP_s390x_linux) # define N_CFI_REGS 66 +#elif defined(VGP_riscv64_linux) +# define N_CFI_REGS 128 #else # define N_CFI_REGS 20 #endif @@ -2310,6 +2316,10 @@ static void initUnwindContext ( /*OUT*/UnwindContext* ctx ) start out as RR_Same. */ ctx->state[j].reg[29/*FP*/].tag = RR_Same; ctx->state[j].reg[30/*LR*/].tag = RR_Same; +# elif defined(VGA_riscv64) + /* Registers fp and ra start out implicitly as RR_Same. */ + ctx->state[j].reg[FP_REG].tag = RR_Same; + ctx->state[j].reg[RA_REG_DEFAULT].tag = RR_Same; # endif } } @@ -2392,7 +2402,8 @@ static Bool summarise_context(/*OUT*/Addr* base, if (ctxs->cfa_is_regoff && ctxs->cfa_reg == SP_REG) { si_m->cfa_off = ctxs->cfa_off; # if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x) \ - || defined(VGA_mips32) || defined(VGA_nanomips) || defined(VGA_mips64) + || defined(VGA_mips32) || defined(VGA_nanomips) \ + || defined(VGA_mips64) || defined(VGA_riscv64) si_m->cfa_how = CFIC_IA_SPREL; # elif defined(VGA_arm) si_m->cfa_how = CFIC_ARM_R13REL; @@ -2406,7 +2417,8 @@ static Bool summarise_context(/*OUT*/Addr* base, if (ctxs->cfa_is_regoff && ctxs->cfa_reg == FP_REG) { si_m->cfa_off = ctxs->cfa_off; # if defined(VGA_x86) || defined(VGA_amd64) || defined(VGA_s390x) \ - || defined(VGA_mips32) || defined(VGA_nanomips) || defined(VGA_mips64) + || defined(VGA_mips32) || defined(VGA_nanomips) \ + || defined(VGA_mips64) || defined(VGA_riscv64) si_m->cfa_how = CFIC_IA_BPREL; # elif defined(VGA_arm) si_m->cfa_how = CFIC_ARM_R12REL; @@ -2786,6 +2798,30 @@ static Bool summarise_context(/*OUT*/Addr* base, # elif defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le) /* These don't use CFI based unwinding (is that really true?) */ +# elif defined(VGA_riscv64) + + /* --- entire tail of this fn specialised for riscv64 --- */ + + SUMMARISE_HOW(si_m->ra_how, si_m->ra_off, ctxs->reg[ctx->ra_reg]); + SUMMARISE_HOW(si_m->fp_how, si_m->fp_off, ctxs->reg[FP_REG]); + + /* on riscv64, it seems the old sp value before the call is always + the same as the CFA. Therefore ... */ + si_m->sp_how = CFIR_CFAREL; + si_m->sp_off = 0; + + /* bogus looking range? Note, we require that the difference is + representable in 32 bits. */ + if (loc_start >= ctx->loc) + { why = 4; goto failed; } + if (ctx->loc - loc_start > 10000000 /* let's say */) + { why = 5; goto failed; } + + *base = loc_start + ctx->initloc; + *len = (UInt)(ctx->loc - loc_start); + + return True; + # else # error "Unknown arch" # endif @@ -2884,7 +2920,7 @@ static Int copy_convert_CfiExpr_tree ( XArray* dstxa, if (dwreg == srcuc->ra_reg) return ML_(CfiExpr_CfiReg)( dstxa, Creg_ARM64_X30 ); # elif defined(VGA_ppc32) || defined(VGA_ppc64be) \ - || defined(VGA_ppc64le) + || defined(VGA_ppc64le) || defined(VGA_riscv64) # else # error "Unknown arch" # endif diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index 77ed4798b0..1dadbc72c5 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -1786,7 +1786,8 @@ static HChar* readlink_path (const HChar *path) while (tries > 0) { SysRes res; -#if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +#if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); #elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) @@ -2711,6 +2712,7 @@ Bool ML_(read_elf_object) ( struct _DebugInfo* di ) || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) \ || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \ || defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) \ || defined(VGP_arm64_freebsd) diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index ef6a400510..12ad681304 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -260,6 +260,11 @@ void ML_(ppDiCfSI) ( const XArray* /* of CfiExpr */ exprs, SHOW_HOW(si_m->x30_how, si_m->x30_off); VG_(printf)(" X29="); SHOW_HOW(si_m->x29_how, si_m->x29_off); +# elif defined(VGA_riscv64) + VG_(printf)(" SP="); + SHOW_HOW(si_m->sp_how, si_m->sp_off); + VG_(printf)(" FP="); + SHOW_HOW(si_m->fp_how, si_m->fp_off); # else # error "Unknown arch" # endif diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c index cad95bcbe2..225e5a0854 100644 --- a/coregrind/m_debuglog.c +++ b/coregrind/m_debuglog.c @@ -637,6 +637,34 @@ static UInt local_sys_getpid ( void ) return a0; } +#elif defined(VGP_riscv64_linux) + +static UInt local_sys_write_stderr ( const HChar* buf, Int n ) +{ + register RegWord a0 asm("a0") = 2; /* stderr */ + register RegWord a1 asm("a1") = (RegWord)buf; + register RegWord a2 asm("a2") = n; + register RegWord a7 asm("a7") = __NR_write; + __asm__ volatile ( + "ecall\n" + : "+r" (a0) + : "r" (a1), "r" (a2), "r" (a7) + ); + return a0 >= 0 ? (UInt)a0 : -1; +} + +static UInt local_sys_getpid ( void ) +{ + register RegWord a0 asm("a0"); + register RegWord a7 asm("a7") = __NR_getpid; + __asm__ volatile ( + "ecall\n" + : "=r" (a0) + : "r" (a7) + ); + return (UInt)a0; +} + #elif defined(VGP_x86_solaris) static UInt local_sys_write_stderr ( const HChar* buf, Int n ) { diff --git a/coregrind/m_gdbserver/target.c b/coregrind/m_gdbserver/target.c index f9f32f4aa5..4238c608cb 100644 --- a/coregrind/m_gdbserver/target.c +++ b/coregrind/m_gdbserver/target.c @@ -867,6 +867,8 @@ void valgrind_initialize_target(void) mips64_init_architecture(&the_low_target); #elif defined(VGA_nanomips) nanomips_init_architecture(&the_low_target); +#elif defined(VGA_riscv64) + riscv64_init_architecture(&the_low_target); #else #error "architecture missing in target.c valgrind_initialize_target" #endif diff --git a/coregrind/m_gdbserver/valgrind_low.h b/coregrind/m_gdbserver/valgrind_low.h index d8ae3c9086..ef4e190897 100644 --- a/coregrind/m_gdbserver/valgrind_low.h +++ b/coregrind/m_gdbserver/valgrind_low.h @@ -109,5 +109,6 @@ extern void s390x_init_architecture (struct valgrind_target_ops *target); extern void mips32_init_architecture (struct valgrind_target_ops *target); extern void mips64_init_architecture (struct valgrind_target_ops *target); extern void nanomips_init_architecture (struct valgrind_target_ops *target); +extern void riscv64_init_architecture (struct valgrind_target_ops *target); #endif diff --git a/coregrind/m_initimg/initimg-linux.c b/coregrind/m_initimg/initimg-linux.c index feec1e5f11..483b7a3ddd 100644 --- a/coregrind/m_initimg/initimg-linux.c +++ b/coregrind/m_initimg/initimg-linux.c @@ -910,9 +910,13 @@ Addr setup_client_stack( void* init_sp, && !defined(VGP_ppc64le_linux) \ && !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux) \ && !defined(VGP_nanomips_linux) \ - && !defined(VGP_s390x_linux) + && !defined(VGP_s390x_linux) \ + && !defined(VGP_riscv64_linux) case AT_SYSINFO_EHDR: { /* Trash this, because we don't reproduce it */ + /* riscv64-linux: Keep the VDSO mapping on this platform present. + It contains __vdso_rt_sigreturn() which the kernel sets the ra + register to point to on a signal delivery. */ const NSegment* ehdrseg = VG_(am_find_nsegment)((Addr)auxv->u.a_ptr); vg_assert(ehdrseg); VG_(am_munmap_valgrind)(ehdrseg->start, ehdrseg->end - ehdrseg->start); @@ -1341,6 +1345,35 @@ void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii ) arch->vex.guest_PC = iifii.initial_client_IP; arch->vex.guest_r31 = iifii.initial_client_SP; +# elif defined(VGP_riscv64_linux) + vg_assert(0 == sizeof(VexGuestRISCV64State) % LibVEX_GUEST_STATE_ALIGN); + + /* Zero out the initial state. */ + LibVEX_GuestRISCV64_initialise(&arch->vex); + + /* Mark all registers as undefined ... */ + VG_(memset)(&arch->vex_shadow1, 0xFF, sizeof(VexGuestRISCV64State)); + VG_(memset)(&arch->vex_shadow2, 0x00, sizeof(VexGuestRISCV64State)); + /* ... except x2 (sp), pc and fcsr. */ + arch->vex_shadow1.guest_x2 = 0; + arch->vex_shadow1.guest_pc = 0; + arch->vex_shadow1.guest_fcsr = 0; + + /* Put essential stuff into the new state. */ + arch->vex.guest_x2 = iifii.initial_client_SP; + arch->vex.guest_pc = iifii.initial_client_IP; + /* Initialize fcsr in the same way as done by the Linux kernel: + accrued exception flags cleared; round to nearest, ties to even. */ + arch->vex.guest_fcsr = 0; + + /* Tell the tool about the registers we just wrote. */ + VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_STACK_PTR, 8); + VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, VG_O_INSTR_PTR, 8); + VG_TRACK(post_reg_write, Vg_CoreStartup, /*tid*/1, + offsetof(VexGuestRISCV64State, guest_fcsr), 4); + +#define PRECISE_GUEST_REG_DEFINEDNESS_AT_STARTUP 1 + # else # error Unknown platform # endif diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c index 257c26bc63..c6380d4e0b 100644 --- a/coregrind/m_libcassert.c +++ b/coregrind/m_libcassert.c @@ -264,6 +264,25 @@ (srP)->misc.MIPS32.r31 = (UInt)ra; \ (srP)->misc.MIPS32.r28 = (UInt)gp; \ } +#elif defined(VGP_riscv64_linux) +# define GET_STARTREGS(srP) \ + { ULong pc, sp, fp, ra; \ + __asm__ __volatile__( \ + "jal %0, 0f;" \ + "0:\n" \ + "mv %1, sp;" \ + "mv %2, fp;" \ + "mv %3, ra;" \ + : "=r" (pc), \ + "=r" (sp), \ + "=r" (fp), \ + "=r" (ra) \ + ); \ + (srP)->r_pc = pc; \ + (srP)->r_sp = sp; \ + (srP)->misc.RISCV64.r_fp = fp; \ + (srP)->misc.RISCV64.r_ra = ra; \ + } #else # error Unknown platform #endif diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c index fb93b4867c..e132e76597 100644 --- a/coregrind/m_libcfile.c +++ b/coregrind/m_libcfile.c @@ -264,8 +264,9 @@ Bool VG_(resolve_filemode) ( Int fd, Int * result ) SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev ) { -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) - /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */ +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) + /* More recent Linux platforms have only __NR_mknodat and no __NR_mknod. */ SysRes res = VG_(do_syscall4)(__NR_mknodat, VKI_AT_FDCWD, (UWord)pathname, mode, dev); # elif defined(VGO_linux) || defined(VGO_darwin) @@ -290,8 +291,9 @@ SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev ) SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode ) { -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) - /* ARM64 wants to use __NR_openat rather than __NR_open. */ +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) + /* More recent Linux platforms have only __NR_openat and no __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); # elif defined(VGO_linux) || defined(VGO_freebsd) @@ -384,7 +386,8 @@ Int VG_(pipe) ( Int fd[2] ) } else { return -1; } -# elif defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# elif defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) SysRes res = VG_(do_syscall2)(__NR_pipe2, (UWord)fd, 0); return sr_isError(res) ? -1 : 0; # elif defined(VGO_linux) @@ -731,7 +734,8 @@ SysRes VG_(dup) ( Int oldfd ) SysRes VG_(dup2) ( Int oldfd, Int newfd ) { -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) /* We only have dup3, that means we have to mimic dup2. The only real difference is when oldfd == newfd. dup3 always returns an error, but dup2 returns only an @@ -777,7 +781,7 @@ Int VG_(rename) ( const HChar* old_name, const HChar* new_name ) # if defined(VGO_solaris) || defined(VGP_arm64_linux) SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name, VKI_AT_FDCWD, (UWord)new_name); -# elif defined(VGP_nanomips_linux) +# elif defined(VGP_nanomips_linux) || defined(VGP_riscv64_linux) SysRes res = VG_(do_syscall5)(__NR_renameat2, VKI_AT_FDCWD, (UWord)old_name, VKI_AT_FDCWD, (UWord)new_name, 0); @@ -791,7 +795,8 @@ Int VG_(rename) ( const HChar* old_name, const HChar* new_name ) Int VG_(unlink) ( const HChar* file_name ) { -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD, (UWord)file_name); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) @@ -870,8 +875,9 @@ const HChar *VG_(get_startup_wd) ( void ) SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout) { SysRes res; -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) - /* ARM64 wants to use __NR_ppoll rather than __NR_poll. */ +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) + /* More recent Linux platforms have only __NR_ppoll and no __NR_poll. */ struct vki_timespec timeout_ts; if (timeout >= 0) { timeout_ts.tv_sec = timeout / 1000; @@ -915,7 +921,8 @@ SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz) { SysRes res; /* res = readlink( path, buf, bufsiz ); */ -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) @@ -994,7 +1001,8 @@ Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr ) UWord w = (irusr ? VKI_R_OK : 0) | (iwusr ? VKI_W_OK : 0) | (ixusr ? VKI_X_OK : 0); -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); @@ -1140,7 +1148,8 @@ SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset ) return res; # elif defined(VGP_amd64_linux) || defined(VGP_s390x_linux) \ || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ - || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) + || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset); return res; # elif defined(VGP_amd64_freebsd) || defined(VGP_arm64_freebsd) @@ -1405,7 +1414,8 @@ Int VG_(socket) ( Int domain, Int type, Int protocol ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_socket, domain, type, protocol ); return sr_isError(res) ? -1 : sr_Res(res); @@ -1460,7 +1470,8 @@ Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen); return sr_isError(res) ? -1 : sr_Res(res); @@ -1507,7 +1518,8 @@ Int VG_(write_socket)( Int sd, const void *msg, Int count ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg, count, VKI_MSG_NOSIGNAL, 0,0); @@ -1544,8 +1556,8 @@ Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ - || defined(VGP_nanomips_linux) || defined(VGO_freebsd) \ - || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) + || defined(VGP_nanomips_linux) || defined(VGP_riscv64_linux) \ + || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)( __NR_getsockname, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1584,7 +1596,8 @@ Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ - || defined(VGP_nanomips_linux) || defined(VGO_freebsd) + || defined(VGP_nanomips_linux) || defined(VGP_riscv64_linux) \ + || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)( __NR_getpeername, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1626,7 +1639,7 @@ Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval, # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ - || defined(VGO_freebsd) + || defined(VGP_riscv64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall5)( __NR_getsockopt, (UWord)sd, (UWord)level, (UWord)optname, @@ -1670,7 +1683,8 @@ Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval, # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) SysRes res; res = VG_(do_syscall5)( __NR_setsockopt, (UWord)sd, (UWord)level, (UWord)optname, diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c index 280ab1cff2..c70f229e5d 100644 --- a/coregrind/m_libcproc.c +++ b/coregrind/m_libcproc.c @@ -698,7 +698,8 @@ Int VG_(gettid)(void) * the /proc/self link is pointing... */ -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)"/proc/self", (UWord)pid, sizeof(pid)); @@ -753,7 +754,8 @@ Int VG_(getpid) ( void ) Int VG_(getpgrp) ( void ) { /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) return sr_Res( VG_(do_syscall1)(__NR_getpgid, 0) ); # elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return sr_Res( VG_(do_syscall0)(__NR_getpgrp) ); @@ -850,7 +852,7 @@ Int VG_(getgroups)( Int size, UInt* list ) || defined(VGO_darwin) || defined(VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_arm64_linux) \ || defined(VGO_solaris) || defined(VGP_nanomips_linux) \ - || defined(VGO_freebsd) + || defined(VGP_riscv64_linux) || defined(VGO_freebsd) SysRes sres; sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list); if (sr_isError(sres)) @@ -951,7 +953,8 @@ Int VG_(fork) ( void ) fds[0] = fds[1] = -1; } -# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) +# if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGP_riscv64_linux) SysRes res; res = VG_(do_syscall5)(__NR_clone, VKI_SIGCHLD, (UWord)NULL, (UWord)NULL, (UWord)NULL, (UWord)NULL); @@ -1426,10 +1429,22 @@ void VG_(invalidate_icache) ( void *ptr, SizeT nbytes ) (UWord) nbytes, (UWord) 3); vg_assert( !sr_isError(sres) ); -# elif defined(VGA_nanomips) - +# elif defined(VGA_nanomips) __builtin___clear_cache(ptr, (char*)ptr + nbytes); +# elif defined(VGP_riscv64_linux) + /* Make data stores to the area visible to all RISC-V harts. */ + __asm__ __volatile__("fence w,r"); + + /* Ask the kernel to execute fence.i on all harts to guarantee that an + instruction fetch on each hart will see any previous data stores visible + to the same hart. */ + Addr startaddr = (Addr)ptr; + Addr endaddr = startaddr + nbytes; + SysRes sres = VG_(do_syscall3)(__NR_riscv_flush_icache, startaddr, endaddr, + 0 /*flags*/); + vg_assert(!sr_isError(sres)); + # endif } diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 234efb312d..dec4f2373e 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -152,6 +152,11 @@ void VG_(get_UnwindStartRegs) ( /*OUT*/UnwindStartRegs* regs, = VG_(threads)[tid].arch.vex.guest_r31; regs->misc.MIPS64.r28 = VG_(threads)[tid].arch.vex.guest_r28; +# elif defined(VGA_riscv64) + regs->r_pc = VG_(threads)[tid].arch.vex.guest_pc; + regs->r_sp = VG_(threads)[tid].arch.vex.guest_x2; + regs->misc.RISCV64.r_fp = VG_(threads)[tid].arch.vex.guest_x8; + regs->misc.RISCV64.r_ra = VG_(threads)[tid].arch.vex.guest_x1; # else # error "Unknown arch" # endif @@ -369,6 +374,39 @@ static void apply_to_GPs_of_tid(ThreadId tid, void (*f)(ThreadId, (*f)(tid, "x28", vex->guest_X28); (*f)(tid, "x29", vex->guest_X29); (*f)(tid, "x30", vex->guest_X30); +#elif defined(VGA_riscv64) + (*f)(tid, "x0" , vex->guest_x0 ); + (*f)(tid, "x1" , vex->guest_x1 ); + (*f)(tid, "x2" , vex->guest_x2 ); + (*f)(tid, "x3" , vex->guest_x3 ); + (*f)(tid, "x4" , vex->guest_x4 ); + (*f)(tid, "x5" , vex->guest_x5 ); + (*f)(tid, "x6" , vex->guest_x6 ); + (*f)(tid, "x7" , vex->guest_x7 ); + (*f)(tid, "x8" , vex->guest_x8 ); + (*f)(tid, "x9" , vex->guest_x9 ); + (*f)(tid, "x10", vex->guest_x10); + (*f)(tid, "x11", vex->guest_x11); + (*f)(tid, "x12", vex->guest_x12); + (*f)(tid, "x13", vex->guest_x13); + (*f)(tid, "x14", vex->guest_x14); + (*f)(tid, "x15", vex->guest_x15); + (*f)(tid, "x16", vex->guest_x16); + (*f)(tid, "x17", vex->guest_x17); + (*f)(tid, "x18", vex->guest_x18); + (*f)(tid, "x19", vex->guest_x19); + (*f)(tid, "x20", vex->guest_x20); + (*f)(tid, "x21", vex->guest_x21); + (*f)(tid, "x22", vex->guest_x22); + (*f)(tid, "x23", vex->guest_x23); + (*f)(tid, "x24", vex->guest_x24); + (*f)(tid, "x25", vex->guest_x25); + (*f)(tid, "x26", vex->guest_x26); + (*f)(tid, "x27", vex->guest_x27); + (*f)(tid, "x28", vex->guest_x28); + (*f)(tid, "x29", vex->guest_x29); + (*f)(tid, "x30", vex->guest_x30); + (*f)(tid, "x31", vex->guest_x31); #else # error Unknown arch #endif @@ -2241,6 +2279,22 @@ Bool VG_(machine_get_hwcaps)( void ) return True; } + +#elif defined(VGA_riscv64) + { + va = VexArchRISCV64; + vai.endness = VexEndnessLE; + + /* Hardware baseline is RV64GC. */ + vai.hwcaps = 0; + + VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps); + + VG_(machine_get_cache_info)(&vai); + + return True; + } + #else # error "Unknown arch" #endif @@ -2381,6 +2435,10 @@ Int VG_(machine_get_size_of_largest_guest_register) ( void ) # elif defined(VGA_mips64) return 8; +# elif defined(VGA_riscv64) + /* 64-bit integer and floating-point registers, no vector set. */ + return 8; + # else # error "Unknown arch" # endif @@ -2397,7 +2455,7 @@ void* VG_(fnptr_to_fnentry)( void* f ) || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \ - || defined(VGP_nanomips_linux) + || defined(VGP_nanomips_linux) || defined(VGP_riscv64_linux) return f; # elif defined(VGP_ppc64be_linux) /* ppc64-linux uses the AIX scheme, in which f is a pointer to a diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 3f07e57a91..877e6b0b68 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -2554,6 +2554,11 @@ static void final_tidyup(ThreadId tid) VG_TRACK(post_reg_write, Vg_CoreClientReq, tid, offsetof(VexGuestPPC64State, guest_GPR3), sizeof(VG_(threads)[tid].arch.vex.guest_GPR3)); +# elif defined(VGA_riscv64) + VG_(threads)[tid].arch.vex.guest_x10 = to_run; + VG_TRACK(post_reg_write, Vg_CoreClientReq, tid, + offsetof(VexGuestRISCV64State, guest_x10), + sizeof(VG_(threads)[tid].arch.vex.guest_x10)); # elif defined(VGA_s390x) VG_(threads)[tid].arch.vex.guest_r2 = to_run; VG_TRACK(post_reg_write, Vg_CoreClientReq, tid, @@ -3087,6 +3092,33 @@ asm( ".set pop \n\t" ".previous \n\t" ); +#elif defined(VGP_riscv64_linux) +asm("\n" + "\t.text\n" + "\t.type _start,@function\n" + "\t.global _start\n" + "_start:\n" + /* establish the global pointer in gp */ + ".option push\n" + ".option norelax\n" + "\tla gp, __global_pointer$\n" + ".option pop\n" + /* set up the new stack in t0 */ + "\tla t0, vgPlain_interim_stack\n" + "\tli t1, "VG_STRINGIFY(VG_STACK_GUARD_SZB)"\n" + "\tadd t0, t0, t1\n" + "\tli t1, "VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)"\n" + "\tadd t0, t0, t1\n" + "\tli t1, 0xFFFFFF00\n" + "\tand t0, t0, t1\n" + /* install it, and collect the original one */ + "\tmv a0, sp\n" + "\tmv sp, t0\n" + /* call _start_in_C_linux, passing it the startup sp */ + "\tj _start_in_C_linux\n" + "\tunimp\n" + ".previous\n" +); #els... [truncated message content] |
From: Mark W. <ma...@so...> - 2025-02-25 16:52:29
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=c01bc3e869d4575c4efd16989d8ef58bcbb14325 commit c01bc3e869d4575c4efd16989d8ef58bcbb14325 Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:42 2023 +0000 riscv64: Add initial support: new port-specific test files The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> https://bugs.kde.org/show_bug.cgi?id=493507 Diff: --- memcheck/tests/riscv64-linux/Makefile.am | 18 + memcheck/tests/riscv64-linux/context_float.c | 548 ++++++ .../tests/riscv64-linux/context_float.stderr.exp | 299 ++++ .../tests/riscv64-linux/context_float.stdout.exp | 102 ++ memcheck/tests/riscv64-linux/context_float.vgtest | 2 + memcheck/tests/riscv64-linux/context_integer.c | 374 ++++ .../tests/riscv64-linux/context_integer.stderr.exp | 216 +++ .../tests/riscv64-linux/context_integer.stdout.exp | 69 + .../tests/riscv64-linux/context_integer.vgtest | 2 + memcheck/tests/riscv64-linux/filter_stderr | 3 + memcheck/tests/riscv64-linux/scalar.c | 127 ++ memcheck/tests/riscv64-linux/scalar.stderr.exp | 156 ++ memcheck/tests/riscv64-linux/scalar.vgtest | 3 + none/tests/riscv64/Makefile.am | 31 + none/tests/riscv64/allexec.c | 1 + none/tests/riscv64/atomic.c | 280 +++ none/tests/riscv64/atomic.stderr.exp | 0 none/tests/riscv64/atomic.stdout.exp | 467 +++++ none/tests/riscv64/atomic.vgtest | 2 + none/tests/riscv64/compressed.c | 456 +++++ none/tests/riscv64/compressed.stderr.exp | 0 none/tests/riscv64/compressed.stdout.exp | 917 ++++++++++ none/tests/riscv64/compressed.vgtest | 2 + none/tests/riscv64/csr.c | 96 + none/tests/riscv64/csr.stderr.exp | 0 none/tests/riscv64/csr.stdout.exp | 145 ++ none/tests/riscv64/csr.vgtest | 2 + none/tests/riscv64/filter_stderr | 3 + none/tests/riscv64/float32.c | 1588 +++++++++++++++++ none/tests/riscv64/float32.stderr.exp | 0 none/tests/riscv64/float32.stdout.exp | 1556 ++++++++++++++++ none/tests/riscv64/float32.vgtest | 2 + none/tests/riscv64/float64.c | 1580 +++++++++++++++++ none/tests/riscv64/float64.stderr.exp | 0 none/tests/riscv64/float64.stdout.exp | 1551 ++++++++++++++++ none/tests/riscv64/float64.vgtest | 2 + none/tests/riscv64/integer.c | 823 +++++++++ none/tests/riscv64/integer.stderr.exp | 0 none/tests/riscv64/integer.stdout.exp | 1858 ++++++++++++++++++++ none/tests/riscv64/integer.vgtest | 2 + none/tests/riscv64/muldiv.c | 351 ++++ none/tests/riscv64/muldiv.stderr.exp | 0 none/tests/riscv64/muldiv.stdout.exp | 435 +++++ none/tests/riscv64/muldiv.vgtest | 2 + none/tests/riscv64/testinst.h | 758 ++++++++ 45 files changed, 14829 insertions(+) diff --git a/memcheck/tests/riscv64-linux/Makefile.am b/memcheck/tests/riscv64-linux/Makefile.am new file mode 100644 index 0000000000..b2757b7cae --- /dev/null +++ b/memcheck/tests/riscv64-linux/Makefile.am @@ -0,0 +1,18 @@ + +include $(top_srcdir)/Makefile.tool-tests.am + +dist_noinst_SCRIPTS = filter_stderr + +EXTRA_DIST = \ + context_float.stdout.exp context_float.stderr.exp context_float.vgtest \ + context_integer.stdout.exp context_integer.stderr.exp context_integer.vgtest \ + scalar.stderr.exp scalar.vgtest + +check_PROGRAMS = \ + context_float \ + context_integer \ + scalar + +AM_CFLAGS += @FLAG_M64@ +AM_CXXFLAGS += @FLAG_M64@ +AM_CCASFLAGS += @FLAG_M64@ diff --git a/memcheck/tests/riscv64-linux/context_float.c b/memcheck/tests/riscv64-linux/context_float.c new file mode 100644 index 0000000000..462385a5cf --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_float.c @@ -0,0 +1,548 @@ +/* Test if values in floating-point registers are correctly propagated into and + out of a signal handler and also check that the same applies for + uninitialised values and their origins. + + Register usage in the test: + before signal -> in signal handler -> after return + f0 -- 0,def -> unchanged -> 0,def + f1 -- 0,undef -> unchanged -> 0,undef + f2 -- 0,def -> set to 0,undef -> 0,undef + f3 -- 0,undef -> set to 0,def -> 0,def + f4 -- 1,def -> increment by 1,def -> 2,def + f5 -- 1,undef -> increment by 1,def -> 2,undef + f6 -- 1,def -> increment by 1,undef -> 2,undef + f7 -- 1,undef -> increment by 1,undef -> 2,undef + f8 -- DBL_MAX,def -> unchanged -> DBL_MAX,def + f9 -- DBL_MAX,undef -> unchanged -> DBL_MAX,undef + f10 -- DBL_MAX,def -> set to 0,undef -> 0,undef + f11 -- DBL_MAX,undef -> set to 0,def -> 0,def + f12 -- 0,def -> set to DBL_MAX,def -> DBL_MAX,def + f13 -- 0,undef -> set to DBL_MAX,undef -> DBL_MAX,undef + f14 -- 0,def -> decrement by 0,def -> 0,def + f15 -- 0,undef -> decrement by 0,def -> 0,undef + f16 -- 0,def -> decrement by 0,undef -> 0,undef + f17 -- 0,undef -> decrement by 0,undef -> 0,undef + f18 -- 0,def -> decrement by 1,def -> -1,def + f19 -- 0,undef -> decrement by 1,def -> -1,undef + f20 -- 0,def -> decrement by 1,undef -> -1,undef + f21 -- 0,undef -> decrement by 1,undef -> -1,undef + f22-f30 -- 0,def -> set to 1,undef -> 1,undef + f31 -- 1,undef -> set 0,def -> 0,def + fcsr: + fflags -- 0b10101,def -> set to 0b01010,undef -> 0b01010,undef + frm -- 0b001,undef -> set to 0b100,def -> 0b100,def + */ + +#include <assert.h> +#include <float.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <sys/ucontext.h> +#include <unistd.h> +#include <valgrind.h> + +typedef union { + unsigned long u64; + double f64; +} uf64; + +static ucontext_t uc; +static unsigned long x0, x1; +static unsigned long dbl_max, dbl_p1, dbl_m1, dbl_p2; + +static void sighandler(int sig, siginfo_t* sip, void* arg) +{ + ucontext_t* ucp = (ucontext_t*)arg; + + uc = *ucp; + + /* Reset fcsr so its undefinedness doesn't affect the following calculations. + */ + __asm__ __volatile__("fscsr zero"); + +#define FPREG_MOD(fpreg, op, mod) \ + do { \ + uf64 t1, t2; \ + t1.u64 = fpreg; \ + t2.u64 = mod; \ + t1.f64 op t2.f64; \ + fpreg = t1.u64; \ + } while (0) + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[2], =, x0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[3], =, 0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[4], +=, dbl_p1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[5], +=, dbl_p1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[6], +=, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[7], +=, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[10], =, x0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[11], =, 0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[12], =, dbl_max); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[13], =, dbl_max + x0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[14], -=, 0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[15], -=, 0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[16], -=, x0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[17], -=, x0); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[18], -=, dbl_p1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[19], -=, dbl_p1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[20], -=, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[21], -=, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[22], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[23], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[24], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[25], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[26], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[27], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[28], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[29], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[30], =, dbl_p1 + x1); + FPREG_MOD(ucp->uc_mcontext.__fpregs.__d.__f[31], =, 0); +#undef FPREG_MOD + + ucp->uc_mcontext.__fpregs.__d.__fcsr = + 0b100 << 5 | ((0b01010 | x0) & 0b11111); +} + +int main(void) +{ + /* Uninitialised, but we know px0[0] is 0x0. */ + unsigned long* px0 = malloc(sizeof(*px0)); + x0 = px0[0]; + + /* Uninitialised, but we know px1[0] is 0x0. */ + unsigned long* px1 = malloc(sizeof(*px1)); + x1 = px1[0]; + + uf64 tmp; + tmp.f64 = DBL_MAX; + dbl_max = tmp.u64; + tmp.f64 = 1.0; + dbl_p1 = tmp.u64; + tmp.f64 = -1.0; + dbl_m1 = tmp.u64; + tmp.f64 = 2.0; + dbl_p2 = tmp.u64; + + struct sigaction sa = {}; + sa.sa_sigaction = sighandler; + if (sigaction(SIGUSR1, &sa, NULL)) { + perror("sigaction"); + return 1; + } + + unsigned long regs_in[33] = { + 0, + x0, + 0, + x0, + dbl_p1, + dbl_p1 + x1, + dbl_p1, + dbl_p1 + x1, + dbl_max, + dbl_max + x0, + dbl_max, + dbl_max + x0, + 0, + x0, + 0, + x0, + 0, + x0, + 0, + x0, + 0, + x0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + dbl_p1 + x1, + ((0b001 | x0) & 0b111) << 5 | 0b10101, + }; + unsigned long regs_out[33] = {}; + + pid_t pid = getpid(); + register unsigned long* t0 asm("t0") = regs_in; + register unsigned long* t1 asm("t1") = regs_out; + register unsigned long a7 asm("a7") = SYS_kill; + register unsigned long a0 asm("a0") = pid; + register unsigned long a1 asm("a1") = SIGUSR1; + __asm__ __volatile__( + /* Spill all test registers, keep the 16-byte sp alignment. */ + "add sp, sp, -272\n\t" + "fsd f0, 0(sp)\n\t" + "fsd f1, 8(sp)\n\t" + "fsd f2, 16(sp)\n\t" + "fsd f3, 24(sp)\n\t" + "fsd f4, 32(sp)\n\t" + "fsd f5, 40(sp)\n\t" + "fsd f6, 48(sp)\n\t" + "fsd f7, 56(sp)\n\t" + "fsd f8, 64(sp)\n\t" + "fsd f9, 72(sp)\n\t" + "fsd f10, 80(sp)\n\t" + "fsd f11, 88(sp)\n\t" + "fsd f12, 96(sp)\n\t" + "fsd f13, 104(sp)\n\t" + "fsd f14, 112(sp)\n\t" + "fsd f15, 120(sp)\n\t" + "fsd f16, 128(sp)\n\t" + "fsd f17, 136(sp)\n\t" + "fsd f18, 144(sp)\n\t" + "fsd f19, 152(sp)\n\t" + "fsd f20, 160(sp)\n\t" + "fsd f21, 168(sp)\n\t" + "fsd f22, 176(sp)\n\t" + "fsd f23, 184(sp)\n\t" + "fsd f24, 192(sp)\n\t" + "fsd f25, 200(sp)\n\t" + "fsd f26, 208(sp)\n\t" + "fsd f27, 216(sp)\n\t" + "fsd f28, 224(sp)\n\t" + "fsd f29, 232(sp)\n\t" + "fsd f30, 240(sp)\n\t" + "fsd f31, 248(sp)\n\t" + "frcsr t2\n\t" + "sd t2, 256(sp)\n\t" + + /* Set values in the test registers. */ + "fld f0, 0(%[in])\n\t" + "fld f1, 8(%[in])\n\t" + "fld f2, 16(%[in])\n\t" + "fld f3, 24(%[in])\n\t" + "fld f4, 32(%[in])\n\t" + "fld f5, 40(%[in])\n\t" + "fld f6, 48(%[in])\n\t" + "fld f7, 56(%[in])\n\t" + "fld f8, 64(%[in])\n\t" + "fld f9, 72(%[in])\n\t" + "fld f10, 80(%[in])\n\t" + "fld f11, 88(%[in])\n\t" + "fld f12, 96(%[in])\n\t" + "fld f13, 104(%[in])\n\t" + "fld f14, 112(%[in])\n\t" + "fld f15, 120(%[in])\n\t" + "fld f16, 128(%[in])\n\t" + "fld f17, 136(%[in])\n\t" + "fld f18, 144(%[in])\n\t" + "fld f19, 152(%[in])\n\t" + "fld f20, 160(%[in])\n\t" + "fld f21, 168(%[in])\n\t" + "fld f22, 176(%[in])\n\t" + "fld f23, 184(%[in])\n\t" + "fld f24, 192(%[in])\n\t" + "fld f25, 200(%[in])\n\t" + "fld f26, 208(%[in])\n\t" + "fld f27, 216(%[in])\n\t" + "fld f28, 224(%[in])\n\t" + "fld f29, 232(%[in])\n\t" + "fld f30, 240(%[in])\n\t" + "fld f31, 248(%[in])\n\t" + "ld t2, 256(%[in])\n\t" + "fscsr t2\n\t" + + /* Trigger the signal handler. */ + "ecall\n\t" + + /* Store updated values in the test registers. */ + "fsd f0, 0(%[out])\n\t" + "fsd f1, 8(%[out])\n\t" + "fsd f2, 16(%[out])\n\t" + "fsd f3, 24(%[out])\n\t" + "fsd f4, 32(%[out])\n\t" + "fsd f5, 40(%[out])\n\t" + "fsd f6, 48(%[out])\n\t" + "fsd f7, 56(%[out])\n\t" + "fsd f8, 64(%[out])\n\t" + "fsd f9, 72(%[out])\n\t" + "fsd f10, 80(%[out])\n\t" + "fsd f11, 88(%[out])\n\t" + "fsd f12, 96(%[out])\n\t" + "fsd f13, 104(%[out])\n\t" + "fsd f14, 112(%[out])\n\t" + "fsd f15, 120(%[out])\n\t" + "fsd f16, 128(%[out])\n\t" + "fsd f17, 136(%[out])\n\t" + "fsd f18, 144(%[out])\n\t" + "fsd f19, 152(%[out])\n\t" + "fsd f20, 160(%[out])\n\t" + "fsd f21, 168(%[out])\n\t" + "fsd f22, 176(%[out])\n\t" + "fsd f23, 184(%[out])\n\t" + "fsd f24, 192(%[out])\n\t" + "fsd f25, 200(%[out])\n\t" + "fsd f26, 208(%[out])\n\t" + "fsd f27, 216(%[out])\n\t" + "fsd f28, 224(%[out])\n\t" + "fsd f29, 232(%[out])\n\t" + "fsd f30, 240(%[out])\n\t" + "fsd f31, 248(%[out])\n\t" + "frcsr t2\n\t" + "sd t2, 256(%[out])\n\t" + + /* Restore their original values. */ + "fld f0, 0(sp)\n\t" + "fld f1, 8(sp)\n\t" + "fld f2, 16(sp)\n\t" + "fld f3, 24(sp)\n\t" + "fld f4, 32(sp)\n\t" + "fld f5, 40(sp)\n\t" + "fld f6, 48(sp)\n\t" + "fld f7, 56(sp)\n\t" + "fld f8, 64(sp)\n\t" + "fld f9, 72(sp)\n\t" + "fld f10, 80(sp)\n\t" + "fld f11, 88(sp)\n\t" + "fld f12, 96(sp)\n\t" + "fld f13, 104(sp)\n\t" + "fld f14, 112(sp)\n\t" + "fld f15, 120(sp)\n\t" + "fld f16, 128(sp)\n\t" + "fld f17, 136(sp)\n\t" + "fld f18, 144(sp)\n\t" + "fld f19, 152(sp)\n\t" + "fld f20, 160(sp)\n\t" + "fld f21, 168(sp)\n\t" + "fld f22, 176(sp)\n\t" + "fld f23, 184(sp)\n\t" + "fld f24, 192(sp)\n\t" + "fld f25, 200(sp)\n\t" + "fld f26, 208(sp)\n\t" + "fld f27, 216(sp)\n\t" + "fld f28, 224(sp)\n\t" + "fld f29, 232(sp)\n\t" + "fld f30, 240(sp)\n\t" + "fld f31, 248(sp)\n\t" + "ld t2, 256(sp)\n\t" + "fscsr t2\n\t" + "add sp, sp, 272\n\t" + : + : [in] "r"(t0), [out] "r"(t1), "r"(a7), "r"(a0), "r"(a1) + : "t2", "memory"); + + printf("Values before the signal:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" f0=%#lx\n", regs_in[0]); + printf(" f1=%#lx\n", regs_in[1]); + printf(" f2=%#lx\n", regs_in[2]); + printf(" f3=%#lx\n", regs_in[3]); + printf(" f4=%#lx\n", regs_in[4]); + printf(" f5=%#lx\n", regs_in[5]); + printf(" f6=%#lx\n", regs_in[6]); + printf(" f7=%#lx\n", regs_in[7]); + printf(" f8=%#lx\n", regs_in[8]); + printf(" f9=%#lx\n", regs_in[9]); + printf(" f10=%#lx\n", regs_in[10]); + printf(" f11=%#lx\n", regs_in[11]); + printf(" f12=%#lx\n", regs_in[12]); + printf(" f13=%#lx\n", regs_in[13]); + printf(" f14=%#lx\n", regs_in[14]); + printf(" f15=%#lx\n", regs_in[15]); + printf(" f16=%#lx\n", regs_in[16]); + printf(" f17=%#lx\n", regs_in[17]); + printf(" f18=%#lx\n", regs_in[18]); + printf(" f19=%#lx\n", regs_in[19]); + printf(" f20=%#lx\n", regs_in[20]); + printf(" f21=%#lx\n", regs_in[21]); + printf(" f22=%#lx\n", regs_in[22]); + printf(" f23=%#lx\n", regs_in[23]); + printf(" f24=%#lx\n", regs_in[24]); + printf(" f25=%#lx\n", regs_in[25]); + printf(" f26=%#lx\n", regs_in[26]); + printf(" f27=%#lx\n", regs_in[27]); + printf(" f28=%#lx\n", regs_in[28]); + printf(" f29=%#lx\n", regs_in[29]); + printf(" f30=%#lx\n", regs_in[30]); + printf(" f31=%#lx\n", regs_in[31]); + printf(" fcsr=%#lx\n", regs_in[32]); + VALGRIND_ENABLE_ERROR_REPORTING; + /* Check which registers contain uninitialized values. */ + assert(regs_in[0] == 0); + assert(regs_in[1] == 0); + assert(regs_in[2] == 0); + assert(regs_in[3] == 0); + assert(regs_in[4] == dbl_p1); + assert(regs_in[5] == dbl_p1); + assert(regs_in[6] == dbl_p1); + assert(regs_in[7] == dbl_p1); + assert(regs_in[8] == dbl_max); + assert(regs_in[9] == dbl_max); + assert(regs_in[10] == dbl_max); + assert(regs_in[11] == dbl_max); + assert(regs_in[12] == 0); + assert(regs_in[13] == 0); + assert(regs_in[14] == 0); + assert(regs_in[15] == 0); + assert(regs_in[16] == 0); + assert(regs_in[17] == 0); + assert(regs_in[18] == 0); + assert(regs_in[19] == 0); + assert(regs_in[20] == 0); + assert(regs_in[21] == 0); + assert(regs_in[22] == 0); + assert(regs_in[23] == 0); + assert(regs_in[24] == 0); + assert(regs_in[25] == 0); + assert(regs_in[26] == 0); + assert(regs_in[27] == 0); + assert(regs_in[28] == 0); + assert(regs_in[29] == 0); + assert(regs_in[30] == 0); + assert(regs_in[31] == dbl_p1); + assert(((regs_in[32] >> 0) & 0b11111) == 0b10101); + assert(((regs_in[32] >> 5) & 0b111) == 0b001); + + printf("Values in the signal handler:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" f0=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[0]); + printf(" f1=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[1]); + printf(" f2=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[2]); + printf(" f3=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[3]); + printf(" f4=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[4]); + printf(" f5=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[5]); + printf(" f6=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[6]); + printf(" f7=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[7]); + printf(" f8=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[8]); + printf(" f9=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[9]); + printf(" f10=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[10]); + printf(" f11=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[11]); + printf(" f12=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[12]); + printf(" f13=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[13]); + printf(" f14=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[14]); + printf(" f15=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[15]); + printf(" f16=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[16]); + printf(" f17=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[17]); + printf(" f18=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[18]); + printf(" f19=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[19]); + printf(" f20=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[20]); + printf(" f21=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[21]); + printf(" f22=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[22]); + printf(" f23=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[23]); + printf(" f24=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[24]); + printf(" f25=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[25]); + printf(" f26=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[26]); + printf(" f27=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[27]); + printf(" f28=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[28]); + printf(" f29=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[29]); + printf(" f30=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[30]); + printf(" f31=%#llx\n", uc.uc_mcontext.__fpregs.__d.__f[31]); + printf(" fcsr=%#x\n", uc.uc_mcontext.__fpregs.__d.__fcsr); + VALGRIND_ENABLE_ERROR_REPORTING; + assert(uc.uc_mcontext.__fpregs.__d.__f[0] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[1] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[2] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[3] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[4] == dbl_p1); + assert(uc.uc_mcontext.__fpregs.__d.__f[5] == dbl_p1); + assert(uc.uc_mcontext.__fpregs.__d.__f[6] == dbl_p1); + assert(uc.uc_mcontext.__fpregs.__d.__f[7] == dbl_p1); + assert(uc.uc_mcontext.__fpregs.__d.__f[8] == dbl_max); + assert(uc.uc_mcontext.__fpregs.__d.__f[9] == dbl_max); + assert(uc.uc_mcontext.__fpregs.__d.__f[10] == dbl_max); + assert(uc.uc_mcontext.__fpregs.__d.__f[11] == dbl_max); + assert(uc.uc_mcontext.__fpregs.__d.__f[12] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[13] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[14] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[15] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[16] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[17] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[18] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[19] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[20] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[21] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[22] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[23] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[24] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[25] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[26] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[27] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[28] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[29] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[30] == 0); + assert(uc.uc_mcontext.__fpregs.__d.__f[31] == dbl_p1); + assert(((uc.uc_mcontext.__fpregs.__d.__fcsr >> 0) & 0b11111) == 0b10101); + assert(((uc.uc_mcontext.__fpregs.__d.__fcsr >> 5) & 0b111) == 0b001); + + printf("Values after return from the signal handler:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" f0=%#lx\n", regs_out[0]); + printf(" f1=%#lx\n", regs_out[1]); + printf(" f2=%#lx\n", regs_out[2]); + printf(" f3=%#lx\n", regs_out[3]); + printf(" f4=%#lx\n", regs_out[4]); + printf(" f5=%#lx\n", regs_out[5]); + printf(" f6=%#lx\n", regs_out[6]); + printf(" f7=%#lx\n", regs_out[7]); + printf(" f8=%#lx\n", regs_out[8]); + printf(" f9=%#lx\n", regs_out[9]); + printf(" f10=%#lx\n", regs_out[10]); + printf(" f11=%#lx\n", regs_out[11]); + printf(" f12=%#lx\n", regs_out[12]); + printf(" f13=%#lx\n", regs_out[13]); + printf(" f14=%#lx\n", regs_out[14]); + printf(" f15=%#lx\n", regs_out[15]); + printf(" f16=%#lx\n", regs_out[16]); + printf(" f17=%#lx\n", regs_out[17]); + printf(" f18=%#lx\n", regs_out[18]); + printf(" f19=%#lx\n", regs_out[19]); + printf(" f20=%#lx\n", regs_out[20]); + printf(" f21=%#lx\n", regs_out[21]); + printf(" f22=%#lx\n", regs_out[22]); + printf(" f23=%#lx\n", regs_out[23]); + printf(" f24=%#lx\n", regs_out[24]); + printf(" f25=%#lx\n", regs_out[25]); + printf(" f26=%#lx\n", regs_out[26]); + printf(" f27=%#lx\n", regs_out[27]); + printf(" f28=%#lx\n", regs_out[28]); + printf(" f29=%#lx\n", regs_out[29]); + printf(" f30=%#lx\n", regs_out[30]); + printf(" f31=%#lx\n", regs_out[31]); + printf(" fcsr=%#lx\n", regs_out[32]); + VALGRIND_ENABLE_ERROR_REPORTING; + assert(regs_out[0] == 0); + assert(regs_out[1] == 0); + assert(regs_out[2] == 0); + assert(regs_out[3] == 0); + assert(regs_out[4] == dbl_p2); + assert(regs_out[5] == dbl_p2); + assert(regs_out[6] == dbl_p2); + assert(regs_out[7] == dbl_p2); + assert(regs_out[8] == dbl_max); + assert(regs_out[9] == dbl_max); + assert(regs_out[10] == 0); + assert(regs_out[11] == 0); + assert(regs_out[12] == dbl_max); + assert(regs_out[13] == dbl_max); + assert(regs_out[14] == 0); + assert(regs_out[15] == 0); + assert(regs_out[16] == 0); + assert(regs_out[17] == 0); + assert(regs_out[18] == dbl_m1); + assert(regs_out[19] == dbl_m1); + assert(regs_out[20] == dbl_m1); + assert(regs_out[21] == dbl_m1); + assert(regs_out[22] == dbl_p1); + assert(regs_out[23] == dbl_p1); + assert(regs_out[24] == dbl_p1); + assert(regs_out[25] == dbl_p1); + assert(regs_out[26] == dbl_p1); + assert(regs_out[27] == dbl_p1); + assert(regs_out[28] == dbl_p1); + assert(regs_out[29] == dbl_p1); + assert(regs_out[30] == dbl_p1); + assert(regs_out[31] == 0); + assert(((regs_out[32] >> 0) & 0b11111) == 0b01010); + assert(((regs_out[32] >> 5) & 0b111) == 0b100); + + free(px0); + free(px1); + + return 0; +} diff --git a/memcheck/tests/riscv64-linux/context_float.stderr.exp b/memcheck/tests/riscv64-linux/context_float.stderr.exp new file mode 100644 index 0000000000..34f59181d5 --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_float.stderr.exp @@ -0,0 +1,299 @@ +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:368) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:370) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:372) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:374) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:376) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:378) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:380) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:382) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:384) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:386) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:388) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:398) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:400) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:439) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:441) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:443) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:445) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:447) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:449) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:451) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:453) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:455) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:457) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:459) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:469) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:471) + Uninitialised value was created + at 0x........: main (context_float.c:177) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:510) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:511) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:514) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:515) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:516) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:518) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:519) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:522) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:524) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:525) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:526) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:528) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:529) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:530) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:531) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:532) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:533) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:534) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:535) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:536) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:537) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:538) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:539) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:114) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_float.c:541) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_float.c:110) + diff --git a/memcheck/tests/riscv64-linux/context_float.stdout.exp b/memcheck/tests/riscv64-linux/context_float.stdout.exp new file mode 100644 index 0000000000..588063bf9e --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_float.stdout.exp @@ -0,0 +1,102 @@ +Values before the signal: + f0=0 + f1=0 + f2=0 + f3=0 + f4=0x3ff0000000000000 + f5=0x3ff0000000000000 + f6=0x3ff0000000000000 + f7=0x3ff0000000000000 + f8=0x7fefffffffffffff + f9=0x7fefffffffffffff + f10=0x7fefffffffffffff + f11=0x7fefffffffffffff + f12=0 + f13=0 + f14=0 + f15=0 + f16=0 + f17=0 + f18=0 + f19=0 + f20=0 + f21=0 + f22=0 + f23=0 + f24=0 + f25=0 + f26=0 + f27=0 + f28=0 + f29=0 + f30=0 + f31=0x3ff0000000000000 + fcsr=0x35 +Values in the signal handler: + f0=0 + f1=0 + f2=0 + f3=0 + f4=0x3ff0000000000000 + f5=0x3ff0000000000000 + f6=0x3ff0000000000000 + f7=0x3ff0000000000000 + f8=0x7fefffffffffffff + f9=0x7fefffffffffffff + f10=0x7fefffffffffffff + f11=0x7fefffffffffffff + f12=0 + f13=0 + f14=0 + f15=0 + f16=0 + f17=0 + f18=0 + f19=0 + f20=0 + f21=0 + f22=0 + f23=0 + f24=0 + f25=0 + f26=0 + f27=0 + f28=0 + f29=0 + f30=0 + f31=0x3ff0000000000000 + fcsr=0x35 +Values after return from the signal handler: + f0=0 + f1=0 + f2=0 + f3=0 + f4=0x4000000000000000 + f5=0x4000000000000000 + f6=0x4000000000000000 + f7=0x4000000000000000 + f8=0x7fefffffffffffff + f9=0x7fefffffffffffff + f10=0 + f11=0 + f12=0x7fefffffffffffff + f13=0x7fefffffffffffff + f14=0 + f15=0 + f16=0 + f17=0 + f18=0xbff0000000000000 + f19=0xbff0000000000000 + f20=0xbff0000000000000 + f21=0xbff0000000000000 + f22=0x3ff0000000000000 + f23=0x3ff0000000000000 + f24=0x3ff0000000000000 + f25=0x3ff0000000000000 + f26=0x3ff0000000000000 + f27=0x3ff0000000000000 + f28=0x3ff0000000000000 + f29=0x3ff0000000000000 + f30=0x3ff0000000000000 + f31=0 + fcsr=0x8a diff --git a/memcheck/tests/riscv64-linux/context_float.vgtest b/memcheck/tests/riscv64-linux/context_float.vgtest new file mode 100644 index 0000000000..0f2a88cd2a --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_float.vgtest @@ -0,0 +1,2 @@ +prog: context_float +vgopts: -q --track-origins=yes diff --git a/memcheck/tests/riscv64-linux/context_integer.c b/memcheck/tests/riscv64-linux/context_integer.c new file mode 100644 index 0000000000..070a9f759b --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_integer.c @@ -0,0 +1,374 @@ +/* Test if values in integer registers are correctly propagated into and out of + a signal handler and also check that the same applies for uninitialised + values and their origins. + + Register usage in the test: + zero (x0) -- unused + ra (x1) -- unused + sp (x2) -- unused + gp (x3) -- unused + tp (x4) -- unused + + t0 (x5) -- holds address of regs_in + t1 (x6) -- holds address of regs_out + a0 (x10) -- current pid + a1 (x11) -- SIGUSR1 + a7 (x17) -- SYS_kill + + before signal -> in signal handler -> after return + t2 (x7) -- 0,def -> unchanged -> 0,def + s0 (x8) -- 0,undef -> unchanged -> 0,undef + s1 (x9) -- 0,def -> set to 0,undef -> 0,undef + a2 (x12) -- 0,undef -> set to 0,def -> 0,def + a3 (x13) -- 1,def -> increment by 1,def -> 2,def + a4 (x14) -- 1,undef -> increment by 1,def -> 2,undef + a5 (x15) -- 1,def -> increment by 1,undef -> 2,undef + a6 (x16) -- 1,undef -> increment by 1,undef -> 2,undef + s2 (x18) -- ULONG_MAX,def -> unchanged -> ULONG_MAX,def + s3 (x19) -- ULONG_MAX,undef -> unchanged -> ULONG_MAX,undef + s4 (x20) -- ULONG_MAX,def -> set to 0,undef -> 0,undef + s5 (x21) -- ULONG_MAX,undef -> set to 0,def -> 0,def + s6 (x22) -- 0,def -> set to ULONG_MAX,def -> ULONG_MAX,def + s7 (x23) -- 0,undef -> set to ULONG_MAX,undef -> ULONG_MAX,undef + s8 (x24) -- 0,def -> decrement by 0,def -> 0,def + s9 (x25) -- 0,undef -> decrement by 0,def -> 0,undef + s10 (x26) -- 0,def -> decrement by 0,undef -> 0,undef + s11 (x27) -- 0,undef -> decrement by 0,undef -> 0,undef + t3 (x28) -- 0,def -> decrement by 1,def -> ULONG_MAX,def + t4 (x29) -- 0,undef -> decrement by 1,def -> ULONG_MAX,undef + t5 (x30) -- 0,def -> decrement by 1,undef -> ULONG_MAX,undef + t6 (x31) -- 0,undef -> decrement by 1,undef -> ULONG_MAX,undef + */ + +#include <assert.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/syscall.h> +#include <sys/ucontext.h> +#include <unistd.h> +#include <valgrind.h> + +static ucontext_t uc; +static unsigned long x0, x1; + +static void sighandler(int sig, siginfo_t* sip, void* arg) +{ + ucontext_t* ucp = (ucontext_t*)arg; + + uc = *ucp; + + ucp->uc_mcontext.__gregs[9] = x0; + ucp->uc_mcontext.__gregs[12] = 0; + ucp->uc_mcontext.__gregs[13] += 1; + ucp->uc_mcontext.__gregs[14] += 1; + ucp->uc_mcontext.__gregs[15] += x1; + ucp->uc_mcontext.__gregs[16] += x1; + ucp->uc_mcontext.__gregs[20] = x0; + ucp->uc_mcontext.__gregs[21] = 0; + ucp->uc_mcontext.__gregs[22] = ULONG_MAX; + ucp->uc_mcontext.__gregs[23] = ULONG_MAX + x0; + ucp->uc_mcontext.__gregs[24] -= 0; + ucp->uc_mcontext.__gregs[25] -= 0; + ucp->uc_mcontext.__gregs[26] -= x0; + ucp->uc_mcontext.__gregs[27] -= x0; + ucp->uc_mcontext.__gregs[28] -= 1; + ucp->uc_mcontext.__gregs[29] -= 1; + ucp->uc_mcontext.__gregs[30] -= x1; + ucp->uc_mcontext.__gregs[31] -= x1; +} + +int main(void) +{ + /* Uninitialised, but we know px0[0] is 0x0. */ + unsigned long* px0 = malloc(sizeof(*px0)); + x0 = px0[0]; + + /* Uninitialised, but we know px1[0] is 0x0. */ + unsigned long* px1 = malloc(sizeof(*px1)); + x1 = px1[0] + 1; + + struct sigaction sa = {}; + sa.sa_sigaction = sighandler; + if (sigaction(SIGUSR1, &sa, NULL)) { + perror("sigaction"); + return 1; + } + + unsigned long regs_in[22] = { + 0, x0, + 0, x0, + 1, x1, + 1, x1, + ULONG_MAX, ULONG_MAX + x0, + ULONG_MAX, ULONG_MAX + x0, + 0, x0, + 0, x0, + 0, x0, + 0, x0, + 0, x0, + }; + unsigned long regs_out[22] = {}; + + pid_t pid = getpid(); + register unsigned long* t0 asm("t0") = regs_in; + register unsigned long* t1 asm("t1") = regs_out; + register unsigned long a7 asm("a7") = SYS_kill; + register unsigned long a0 asm("a0") = pid; + register unsigned long a1 asm("a1") = SIGUSR1; + __asm__ __volatile__( + /* Spill all test registers, keep the 16-byte sp alignment. */ + "add sp, sp, -176\n\t" + "sd t2, 0(sp)\n\t" + "sd s0, 8(sp)\n\t" + "sd s1, 16(sp)\n\t" + "sd a2, 24(sp)\n\t" + "sd a3, 32(sp)\n\t" + "sd a4, 40(sp)\n\t" + "sd a5, 48(sp)\n\t" + "sd a6, 56(sp)\n\t" + "sd s2, 64(sp)\n\t" + "sd s3, 72(sp)\n\t" + "sd s4, 80(sp)\n\t" + "sd s5, 88(sp)\n\t" + "sd s6, 96(sp)\n\t" + "sd s7, 104(sp)\n\t" + "sd s8, 112(sp)\n\t" + "sd s9, 120(sp)\n\t" + "sd s10, 128(sp)\n\t" + "sd s11, 136(sp)\n\t" + "sd t3, 144(sp)\n\t" + "sd t4, 152(sp)\n\t" + "sd t5, 160(sp)\n\t" + "sd t6, 168(sp)\n\t" + + /* Set values in the test registers. */ + "ld t2, 0(%[in])\n\t" + "ld s0, 8(%[in])\n\t" + "ld s1, 16(%[in])\n\t" + "ld a2, 24(%[in])\n\t" + "ld a3, 32(%[in])\n\t" + "ld a4, 40(%[in])\n\t" + "ld a5, 48(%[in])\n\t" + "ld a6, 56(%[in])\n\t" + "ld s2, 64(%[in])\n\t" + "ld s3, 72(%[in])\n\t" + "ld s4, 80(%[in])\n\t" + "ld s5, 88(%[in])\n\t" + "ld s6, 96(%[in])\n\t" + "ld s7, 104(%[in])\n\t" + "ld s8, 112(%[in])\n\t" + "ld s9, 120(%[in])\n\t" + "ld s10, 128(%[in])\n\t" + "ld s11, 136(%[in])\n\t" + "ld t3, 144(%[in])\n\t" + "ld t4, 152(%[in])\n\t" + "ld t5, 160(%[in])\n\t" + "ld t6, 168(%[in])\n\t" + + /* Trigger the signal handler. */ + "ecall\n\t" + + /* Store updated values in the test registers. */ + "sd t2, 0(%[out])\n\t" + "sd s0, 8(%[out])\n\t" + "sd s1, 16(%[out])\n\t" + "sd a2, 24(%[out])\n\t" + "sd a3, 32(%[out])\n\t" + "sd a4, 40(%[out])\n\t" + "sd a5, 48(%[out])\n\t" + "sd a6, 56(%[out])\n\t" + "sd s2, 64(%[out])\n\t" + "sd s3, 72(%[out])\n\t" + "sd s4, 80(%[out])\n\t" + "sd s5, 88(%[out])\n\t" + "sd s6, 96(%[out])\n\t" + "sd s7, 104(%[out])\n\t" + "sd s8, 112(%[out])\n\t" + "sd s9, 120(%[out])\n\t" + "sd s10, 128(%[out])\n\t" + "sd s11, 136(%[out])\n\t" + "sd t3, 144(%[out])\n\t" + "sd t4, 152(%[out])\n\t" + "sd t5, 160(%[out])\n\t" + "sd t6, 168(%[out])\n\t" + + /* Restore their original values. */ + "ld t2, 0(sp)\n\t" + "ld s0, 8(sp)\n\t" + "ld s1, 16(sp)\n\t" + "ld a2, 24(sp)\n\t" + "ld a3, 32(sp)\n\t" + "ld a4, 40(sp)\n\t" + "ld a5, 48(sp)\n\t" + "ld a6, 56(sp)\n\t" + "ld s2, 64(sp)\n\t" + "ld s3, 72(sp)\n\t" + "ld s4, 80(sp)\n\t" + "ld s5, 88(sp)\n\t" + "ld s6, 96(sp)\n\t" + "ld s7, 104(sp)\n\t" + "ld s8, 112(sp)\n\t" + "ld s9, 120(sp)\n\t" + "ld s10, 128(sp)\n\t" + "ld s11, 136(sp)\n\t" + "ld t3, 144(sp)\n\t" + "ld t4, 152(sp)\n\t" + "ld t5, 160(sp)\n\t" + "ld t6, 168(sp)\n\t" + "add sp, sp, 176\n\t" + : + : [in] "r"(t0), [out] "r"(t1), "r"(a7), "r"(a0), "r"(a1) + : "memory"); + + printf("Values before the signal:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" t2=%#lx\n", regs_in[0]); + printf(" s0=%#lx\n", regs_in[1]); + printf(" s1=%#lx\n", regs_in[2]); + printf(" a2=%#lx\n", regs_in[3]); + printf(" a3=%#lx\n", regs_in[4]); + printf(" a4=%#lx\n", regs_in[5]); + printf(" a5=%#lx\n", regs_in[6]); + printf(" a6=%#lx\n", regs_in[7]); + printf(" s2=%#lx\n", regs_in[8]); + printf(" s3=%#lx\n", regs_in[9]); + printf(" s4=%#lx\n", regs_in[10]); + printf(" s5=%#lx\n", regs_in[11]); + printf(" s6=%#lx\n", regs_in[12]); + printf(" s7=%#lx\n", regs_in[13]); + printf(" s8=%#lx\n", regs_in[14]); + printf(" s9=%#lx\n", regs_in[15]); + printf(" s10=%#lx\n", regs_in[16]); + printf(" s11=%#lx\n", regs_in[17]); + printf(" t3=%#lx\n", regs_in[18]); + printf(" t4=%#lx\n", regs_in[19]); + printf(" t5=%#lx\n", regs_in[20]); + printf(" t6=%#lx\n", regs_in[21]); + VALGRIND_ENABLE_ERROR_REPORTING; + /* Check which registers contain uninitialized values. */ + assert(regs_in[0] == 0); + assert(regs_in[1] == 0); + assert(regs_in[2] == 0); + assert(regs_in[3] == 0); + assert(regs_in[4] == 1); + assert(regs_in[5] == 1); + assert(regs_in[6] == 1); + assert(regs_in[7] == 1); + assert(regs_in[8] == ULONG_MAX); + assert(regs_in[9] == ULONG_MAX); + assert(regs_in[10] == ULONG_MAX); + assert(regs_in[11] == ULONG_MAX); + assert(regs_in[12] == 0); + assert(regs_in[13] == 0); + assert(regs_in[14] == 0); + assert(regs_in[15] == 0); + assert(regs_in[16] == 0); + assert(regs_in[17] == 0); + assert(regs_in[18] == 0); + assert(regs_in[19] == 0); + assert(regs_in[20] == 0); + assert(regs_in[21] == 0); + + printf("Values in the signal handler:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" t2=%#lx\n", uc.uc_mcontext.__gregs[7]); + printf(" s0=%#lx\n", uc.uc_mcontext.__gregs[8]); + printf(" s1=%#lx\n", uc.uc_mcontext.__gregs[9]); + printf(" a2=%#lx\n", uc.uc_mcontext.__gregs[12]); + printf(" a3=%#lx\n", uc.uc_mcontext.__gregs[13]); + printf(" a4=%#lx\n", uc.uc_mcontext.__gregs[14]); + printf(" a5=%#lx\n", uc.uc_mcontext.__gregs[15]); + printf(" a6=%#lx\n", uc.uc_mcontext.__gregs[16]); + printf(" s2=%#lx\n", uc.uc_mcontext.__gregs[18]); + printf(" s3=%#lx\n", uc.uc_mcontext.__gregs[19]); + printf(" s4=%#lx\n", uc.uc_mcontext.__gregs[20]); + printf(" s5=%#lx\n", uc.uc_mcontext.__gregs[21]); + printf(" s6=%#lx\n", uc.uc_mcontext.__gregs[22]); + printf(" s7=%#lx\n", uc.uc_mcontext.__gregs[23]); + printf(" s8=%#lx\n", uc.uc_mcontext.__gregs[24]); + printf(" s9=%#lx\n", uc.uc_mcontext.__gregs[25]); + printf(" s10=%#lx\n", uc.uc_mcontext.__gregs[26]); + printf(" s11=%#lx\n", uc.uc_mcontext.__gregs[27]); + printf(" t3=%#lx\n", uc.uc_mcontext.__gregs[28]); + printf(" t4=%#lx\n", uc.uc_mcontext.__gregs[29]); + printf(" t5=%#lx\n", uc.uc_mcontext.__gregs[30]); + printf(" t6=%#lx\n", uc.uc_mcontext.__gregs[31]); + VALGRIND_ENABLE_ERROR_REPORTING; + assert(uc.uc_mcontext.__gregs[7] == 0); + assert(uc.uc_mcontext.__gregs[8] == 0); + assert(uc.uc_mcontext.__gregs[9] == 0); + assert(uc.uc_mcontext.__gregs[12] == 0); + assert(uc.uc_mcontext.__gregs[13] == 1); + assert(uc.uc_mcontext.__gregs[14] == 1); + assert(uc.uc_mcontext.__gregs[15] == 1); + assert(uc.uc_mcontext.__gregs[16] == 1); + assert(uc.uc_mcontext.__gregs[18] == ULONG_MAX); + assert(uc.uc_mcontext.__gregs[19] == ULONG_MAX); + assert(uc.uc_mcontext.__gregs[20] == ULONG_MAX); + assert(uc.uc_mcontext.__gregs[21] == ULONG_MAX); + assert(uc.uc_mcontext.__gregs[22] == 0); + assert(uc.uc_mcontext.__gregs[23] == 0); + assert(uc.uc_mcontext.__gregs[24] == 0); + assert(uc.uc_mcontext.__gregs[25] == 0); + assert(uc.uc_mcontext.__gregs[26] == 0); + assert(uc.uc_mcontext.__gregs[27] == 0); + assert(uc.uc_mcontext.__gregs[28] == 0); + assert(uc.uc_mcontext.__gregs[29] == 0); + assert(uc.uc_mcontext.__gregs[30] == 0); + assert(uc.uc_mcontext.__gregs[31] == 0); + + printf("Values after return from the signal handler:\n"); + VALGRIND_DISABLE_ERROR_REPORTING; + printf(" t2=%#lx\n", regs_out[0]); + printf(" s0=%#lx\n", regs_out[1]); + printf(" s1=%#lx\n", regs_out[2]); + printf(" a2=%#lx\n", regs_out[3]); + printf(" a3=%#lx\n", regs_out[4]); + printf(" a4=%#lx\n", regs_out[5]); + printf(" a5=%#lx\n", regs_out[6]); + printf(" a6=%#lx\n", regs_out[7]); + printf(" s2=%#lx\n", regs_out[8]); + printf(" s3=%#lx\n", regs_out[9]); + printf(" s4=%#lx\n", regs_out[10]); + printf(" s5=%#lx\n", regs_out[11]); + printf(" s6=%#lx\n", regs_out[12]); + printf(" s7=%#lx\n", regs_out[13]); + printf(" s8=%#lx\n", regs_out[14]); + printf(" s9=%#lx\n", regs_out[15]); + printf(" s10=%#lx\n", regs_out[16]); + printf(" s11=%#lx\n", regs_out[17]); + printf(" t3=%#lx\n", regs_out[18]); + printf(" t4=%#lx\n", regs_out[19]); + printf(" t5=%#lx\n", regs_out[20]); + printf(" t6=%#lx\n", regs_out[21]); + VALGRIND_ENABLE_ERROR_REPORTING; + assert(regs_out[0] == 0); + assert(regs_out[1] == 0); + assert(regs_out[2] == 0); + assert(regs_out[3] == 0); + assert(regs_out[4] == 2); + assert(regs_out[5] == 2); + assert(regs_out[6] == 2); + assert(regs_out[7] == 2); + assert(regs_out[8] == ULONG_MAX); + assert(regs_out[9] == ULONG_MAX); + assert(regs_out[10] == 0); + assert(regs_out[11] == 0); + assert(regs_out[12] == ULONG_MAX); + assert(regs_out[13] == ULONG_MAX); + assert(regs_out[14] == 0); + assert(regs_out[15] == 0); + assert(regs_out[16] == 0); + assert(regs_out[17] == 0); + assert(regs_out[18] == ULONG_MAX); + assert(regs_out[19] == ULONG_MAX); + assert(regs_out[20] == ULONG_MAX); + assert(regs_out[21] == ULONG_MAX); + + free(px0); + free(px1); + + return 0; +} diff --git a/memcheck/tests/riscv64-linux/context_integer.stderr.exp b/memcheck/tests/riscv64-linux/context_integer.stderr.exp new file mode 100644 index 0000000000..20cf89090e --- /dev/null +++ b/memcheck/tests/riscv64-linux/context_integer.stderr.exp @@ -0,0 +1,216 @@ +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:252) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:254) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:256) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:89) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:258) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:89) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:260) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:262) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:264) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:266) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:268) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:270) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:272) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:300) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:302) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:304) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:89) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:306) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:89) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:308) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:310) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:312) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:314) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:316) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:318) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:320) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (context_integer.c:85) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (context_integer.c:348) + Uninitialised value was created by a heap allocation + at 0... [truncated message content] |
From: Mark W. <ma...@so...> - 2025-02-25 16:52:24
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=98e075fc8976bedfee0861225f8c79e2062c484f commit 98e075fc8976bedfee0861225f8c79e2062c484f Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:42 2023 +0000 riscv64: Add initial support: new port-specific VEX files The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> Some integration fixes were added by Mark Wielaard <ma...@kl...> - Handle Ity_I1, Iex.Const (boolean) https://bugs.kde.org/show_bug.cgi?id=468575 Diff: --- VEX/priv/guest_riscv64_defs.h | 136 ++ VEX/priv/guest_riscv64_helpers.c | 481 ++++++ VEX/priv/guest_riscv64_toIR.c | 3511 ++++++++++++++++++++++++++++++++++++++ VEX/priv/host_riscv64_defs.c | 2696 +++++++++++++++++++++++++++++ VEX/priv/host_riscv64_defs.h | 644 +++++++ VEX/priv/host_riscv64_isel.c | 2097 +++++++++++++++++++++++ VEX/pub/libvex_guest_riscv64.h | 148 ++ 7 files changed, 9713 insertions(+) diff --git a/VEX/priv/guest_riscv64_defs.h b/VEX/priv/guest_riscv64_defs.h new file mode 100644 index 0000000000..ee5435e145 --- /dev/null +++ b/VEX/priv/guest_riscv64_defs.h @@ -0,0 +1,136 @@ + +/*--------------------------------------------------------------------*/ +/*--- begin guest_riscv64_defs.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. + + Neither the names of the U.S. Department of Energy nor the + University of California nor the names of its contributors may be + used to endorse or promote products derived from this software + without prior written permission. +*/ + +/* Only to be used within the guest_riscv64_* files. */ + +#ifndef __VEX_GUEST_RISCV64_DEFS_H +#define __VEX_GUEST_RISCV64_DEFS_H + +#include "libvex_basictypes.h" + +#include "guest_generic_bb_to_IR.h" + +/*------------------------------------------------------------*/ +/*--- riscv64 to IR conversion ---*/ +/*------------------------------------------------------------*/ + +/* Convert one riscv64 insn to IR. See the type DisOneInstrFn in + guest_generic_bb_to_IR.h. */ +DisResult disInstr_RISCV64(IRSB* irbb, + const UChar* guest_code, + Long delta, + Addr guest_IP, + VexArch guest_arch, + const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, + VexEndness host_endness, + Bool sigill_diag); + +/* Used by the optimiser to specialise calls to helpers. */ +IRExpr* guest_riscv64_spechelper(const HChar* function_name, + IRExpr** args, + IRStmt** precedingStmts, + Int n_precedingStmts); + +/* Describes to the optimiser which part of the guest state require precise + memory exceptions. This is logically part of the guest state description. */ +Bool guest_riscv64_state_requires_precise_mem_exns( + Int minoff, Int maxoff, VexRegisterUpdates pxControl); + +extern VexGuestLayout riscv64guest_layout; + +/*------------------------------------------------------------*/ +/*--- riscv64 guest helpers ---*/ +/*------------------------------------------------------------*/ + +/* --- CLEAN HELPERS --- */ + +/* Calculate resulting flags of a specified floating-point operation. Returns + a 32-bit value where bits 4:0 contain the fflags in the RISC-V native + format (NV DZ OF UF NX) and remaining upper bits are zero. */ +UInt riscv64g_calculate_fflags_fsqrt_s(Float a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_w_s(Float a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_wu_s(Float a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_s_w(UInt a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_s_wu(UInt a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_l_s(Float a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_lu_s(Float a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_s_l(ULong a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_s_lu(ULong a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fsqrt_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_s_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_w_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_wu_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_l_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_lu_d(Double a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_d_l(ULong a1, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fcvt_d_lu(ULong a1, UInt rm_RISCV); + +UInt riscv64g_calculate_fflags_fadd_s(Float a1, Float a2, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fmul_s(Float a1, Float a2, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fdiv_s(Float a1, Float a2, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fadd_d(Double a1, Double a2, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fmul_d(Double a1, Double a2, UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fdiv_d(Double a1, Double a2, UInt rm_RISCV); + +UInt riscv64g_calculate_fflags_fmin_s(Float a1, Float a2); +UInt riscv64g_calculate_fflags_fmax_s(Float a1, Float a2); +UInt riscv64g_calculate_fflags_feq_s(Float a1, Float a2); +UInt riscv64g_calculate_fflags_flt_s(Float a1, Float a2); +UInt riscv64g_calculate_fflags_fle_s(Float a1, Float a2); +UInt riscv64g_calculate_fflags_fmin_d(Double a1, Double a2); +UInt riscv64g_calculate_fflags_fmax_d(Double a1, Double a2); +UInt riscv64g_calculate_fflags_feq_d(Double a1, Double a2); +UInt riscv64g_calculate_fflags_flt_d(Double a1, Double a2); +UInt riscv64g_calculate_fflags_fle_d(Double a1, Double a2); + +UInt riscv64g_calculate_fflags_fmadd_s(Float a1, + Float a2, + Float a3, + UInt rm_RISCV); +UInt riscv64g_calculate_fflags_fmadd_d(Double a1, + Double a2, + Double a3, + UInt rm_RISCV); + +/* Calculate floating-point class. Returns a 64-bit value where bits 9:0 + contains the properties in the RISC-V FCLASS-instruction format and remaining + upper bits are zero. */ +ULong riscv64g_calculate_fclass_s(Float a1); +ULong riscv64g_calculate_fclass_d(Double a1); + +#endif /* ndef __VEX_GUEST_RISCV64_DEFS_H */ + +/*--------------------------------------------------------------------*/ +/*--- end guest_riscv64_defs.h ---*/ +/*--------------------------------------------------------------------*/ diff --git a/VEX/priv/guest_riscv64_helpers.c b/VEX/priv/guest_riscv64_helpers.c new file mode 100644 index 0000000000..e7c4ed8055 --- /dev/null +++ b/VEX/priv/guest_riscv64_helpers.c @@ -0,0 +1,481 @@ + +/*--------------------------------------------------------------------*/ +/*--- begin guest_riscv64_helpers.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "libvex_guest_riscv64.h" + +#include "guest_riscv64_defs.h" +#include "main_util.h" + +/* This file contains helper functions for riscv64 guest code. Calls to these + functions are generated by the back end. These calls are of course in the + host machine code and this file will be compiled to host machine code, so + that all makes sense. + + Only change the signatures of these helper functions very carefully. If you + change the signature here, you'll have to change the parameters passed to it + in the IR calls constructed by guest_riscv64_toIR.c. + + The convention used is that all functions called from generated code are + named riscv64g_<something>, and any function whose name lacks that prefix is + not called from generated code. Note that some LibVEX_* functions can however + be called by VEX's client, but that is not the same as calling them from + VEX-generated code. +*/ + +#if defined(__riscv) && (__riscv_xlen == 64) +/* clang-format off */ +#define CALCULATE_FFLAGS_UNARY64_F(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " ft0, %[a1]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1), [rm] "r"(rm_RISCV) \ + : "t0", "ft0"); \ + return res; \ + } while (0) +#define CALCULATE_FFLAGS_UNARY64_IF(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " t1, %[a1]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1), [rm] "r"(rm_RISCV) \ + : "t0", "t1"); \ + return res; \ + } while (0) +#define CALCULATE_FFLAGS_UNARY64_FI(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " ft0, %[a1]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "r"(a1), [rm] "r"(rm_RISCV) \ + : "t0", "ft0"); \ + return res; \ + } while (0) +/* clang-format on */ +#else +/* No simulated version is currently implemented. */ +#define CALCULATE_FFLAGS_UNARY64_F(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#define CALCULATE_FFLAGS_UNARY64_IF(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#define CALCULATE_FFLAGS_UNARY64_FI(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#endif + +/* CALLED FROM GENERATED CODE: CLEAN HELPERS */ +UInt riscv64g_calculate_fflags_fsqrt_s(Float a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_F("fsqrt.s"); +} +UInt riscv64g_calculate_fflags_fcvt_w_s(Float a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.w.s"); +} +UInt riscv64g_calculate_fflags_fcvt_wu_s(Float a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.wu.s"); +} +UInt riscv64g_calculate_fflags_fcvt_s_w(UInt a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.s.w"); +} +UInt riscv64g_calculate_fflags_fcvt_s_wu(UInt a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.s.wu"); +} +UInt riscv64g_calculate_fflags_fcvt_l_s(Float a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.l.s"); +} +UInt riscv64g_calculate_fflags_fcvt_lu_s(Float a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.lu.s"); +} +UInt riscv64g_calculate_fflags_fcvt_s_l(ULong a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.s.l"); +} +UInt riscv64g_calculate_fflags_fcvt_s_lu(ULong a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.s.lu"); +} +UInt riscv64g_calculate_fflags_fsqrt_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_F("fsqrt.d"); +} +UInt riscv64g_calculate_fflags_fcvt_s_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_F("fcvt.s.d"); +} +UInt riscv64g_calculate_fflags_fcvt_w_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.w.d"); +} +UInt riscv64g_calculate_fflags_fcvt_wu_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.wu.d"); +} +UInt riscv64g_calculate_fflags_fcvt_l_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.l.d"); +} +UInt riscv64g_calculate_fflags_fcvt_lu_d(Double a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_IF("fcvt.lu.d"); +} +UInt riscv64g_calculate_fflags_fcvt_d_l(ULong a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.d.l"); +} +UInt riscv64g_calculate_fflags_fcvt_d_lu(ULong a1, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_UNARY64_FI("fcvt.d.lu"); +} + +#if defined(__riscv) && (__riscv_xlen == 64) +/* clang-format off */ +#define CALCULATE_FFLAGS_BINARY64(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " %[a1], %[a1], %[a2]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1), [a2] "f"(a2), [rm] "r"(rm_RISCV) \ + : "t0"); \ + return res; \ + } while (0) +#define CALCULATE_FFLAGS_BINARY64_IFF(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " t1, %[a1], %[a2]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1), [a2] "f"(a2), [rm] "r"(rm_RISCV) \ + : "t0", "t1"); \ + return res; \ + } while (0) +/* clang-format on */ +#else +/* No simulated version is currently implemented. */ +#define CALCULATE_FFLAGS_BINARY64(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#define CALCULATE_FFLAGS_BINARY64_IFF(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#endif + +/* CALLED FROM GENERATED CODE: CLEAN HELPERS */ +UInt riscv64g_calculate_fflags_fadd_s(Float a1, Float a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fadd.s"); +} +UInt riscv64g_calculate_fflags_fmul_s(Float a1, Float a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fmul.s"); +} +UInt riscv64g_calculate_fflags_fdiv_s(Float a1, Float a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fdiv.s"); +} +UInt riscv64g_calculate_fflags_fadd_d(Double a1, Double a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fadd.d"); +} +UInt riscv64g_calculate_fflags_fmul_d(Double a1, Double a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fmul.d"); +} +UInt riscv64g_calculate_fflags_fdiv_d(Double a1, Double a2, UInt rm_RISCV) +{ + CALCULATE_FFLAGS_BINARY64("fdiv.d"); +} +UInt riscv64g_calculate_fflags_fmin_s(Float a1, Float a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64("fmin.s"); +} +UInt riscv64g_calculate_fflags_fmax_s(Float a1, Float a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64("fmax.s"); +} +UInt riscv64g_calculate_fflags_feq_s(Float a1, Float a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("feq.s"); +} +UInt riscv64g_calculate_fflags_flt_s(Float a1, Float a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("flt.s"); +} +UInt riscv64g_calculate_fflags_fle_s(Float a1, Float a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("fle.s"); +} +UInt riscv64g_calculate_fflags_fmin_d(Double a1, Double a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64("fmin.d"); +} +UInt riscv64g_calculate_fflags_fmax_d(Double a1, Double a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64("fmax.d"); +} +UInt riscv64g_calculate_fflags_feq_d(Double a1, Double a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("feq.d"); +} +UInt riscv64g_calculate_fflags_flt_d(Double a1, Double a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("flt.d"); +} +UInt riscv64g_calculate_fflags_fle_d(Double a1, Double a2) +{ + UInt rm_RISCV = 0; /* unused */ + CALCULATE_FFLAGS_BINARY64_IFF("fle.d"); +} + +#if defined(__riscv) && (__riscv_xlen == 64) +/* clang-format off */ +#define CALCULATE_FFLAGS_TERNARY64(inst) \ + do { \ + UInt res; \ + __asm__ __volatile__( \ + "csrr t0, fcsr\n\t" \ + "csrw frm, %[rm]\n\t" \ + "csrw fflags, zero\n\t" \ + inst " %[a1], %[a1], %[a2], %[a3]\n\t" \ + "csrr %[res], fflags\n\t" \ + "csrw fcsr, t0\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1), [a2] "f"(a2), [a3] "f"(a3), [rm] "r"(rm_RISCV) \ + : "t0"); \ + return res; \ + } while (0) +/* clang-format on */ +#else +/* No simulated version is currently implemented. */ +#define CALCULATE_FFLAGS_TERNARY64(inst) \ + do { \ + (void)rm_RISCV; \ + return 0; \ + } while (0) +#endif + +/* CALLED FROM GENERATED CODE: CLEAN HELPERS */ +UInt riscv64g_calculate_fflags_fmadd_s(Float a1, + Float a2, + Float a3, + UInt rm_RISCV) +{ + CALCULATE_FFLAGS_TERNARY64("fmadd.s"); +} +UInt riscv64g_calculate_fflags_fmadd_d(Double a1, + Double a2, + Double a3, + UInt rm_RISCV) +{ + CALCULATE_FFLAGS_TERNARY64("fmadd.d"); +} + +#if defined(__riscv) && (__riscv_xlen == 64) +/* clang-format off */ +#define CALCULATE_FCLASS(inst) \ + do { \ + ULong res; \ + __asm__ __volatile__( \ + inst " %[res], %[a1]\n\t" \ + : [res] "=r"(res) \ + : [a1] "f"(a1)); \ + return res; \ + } while (0) +/* clang-format on */ +#else +/* No simulated version is currently implemented. */ +#define CALCULATE_FCLASS(inst) \ + do { \ + return 0; \ + } while (0) +#endif + +/* CALLED FROM GENERATED CODE: CLEAN HELPERS */ +ULong riscv64g_calculate_fclass_s(Float a1) { CALCULATE_FCLASS("fclass.s"); } +ULong riscv64g_calculate_fclass_d(Double a1) { CALCULATE_FCLASS("fclass.d"); } + +/*------------------------------------------------------------*/ +/*--- Flag-helpers translation-time function specialisers. ---*/ +/*--- These help iropt specialise calls the above run-time ---*/ +/*--- flags functions. ---*/ +/*------------------------------------------------------------*/ + +IRExpr* guest_riscv64_spechelper(const HChar* function_name, + IRExpr** args, + IRStmt** precedingStmts, + Int n_precedingStmts) +{ + return NULL; +} + +/*------------------------------------------------------------*/ +/*--- Helpers for dealing with, and describing, guest ---*/ +/*--- state as a whole. ---*/ +/*------------------------------------------------------------*/ + +/* Initialise the entire riscv64 guest state. */ +/* VISIBLE TO LIBVEX CLIENT */ +void LibVEX_GuestRISCV64_initialise(/*OUT*/ VexGuestRISCV64State* vex_state) +{ + vex_bzero(vex_state, sizeof(*vex_state)); +} + +/* Figure out if any part of the guest state contained in minoff .. maxoff + requires precise memory exceptions. If in doubt return True (but this + generates significantly slower code). + + By default we enforce precise exns for guest x2 (sp), x8 (fp) and pc only. + These are the minimum needed to extract correct stack backtraces from riscv64 + code. + + Only x2 (sp) is needed in mode VexRegUpdSpAtMemAccess. +*/ +Bool guest_riscv64_state_requires_precise_mem_exns(Int minoff, + Int maxoff, + VexRegisterUpdates pxControl) +{ + Int fp_min = offsetof(VexGuestRISCV64State, guest_x8); + Int fp_max = fp_min + 8 - 1; + Int sp_min = offsetof(VexGuestRISCV64State, guest_x2); + Int sp_max = sp_min + 8 - 1; + Int pc_min = offsetof(VexGuestRISCV64State, guest_pc); + Int pc_max = pc_min + 8 - 1; + + if (maxoff < sp_min || minoff > sp_max) { + /* No overlap with sp. */ + if (pxControl == VexRegUpdSpAtMemAccess) + return False; /* We only need to check stack pointer. */ + } else + return True; + + if (maxoff < fp_min || minoff > fp_max) { + /* No overlap with fp. */ + } else + return True; + + if (maxoff < pc_min || minoff > pc_max) { + /* No overlap with pc. */ + } else + return True; + + return False; +} + +#define ALWAYSDEFD(field) \ + { \ + offsetof(VexGuestRISCV64State, field), \ + (sizeof((VexGuestRISCV64State*)0)->field) \ + } + +VexGuestLayout riscv64guest_layout = { + /* Total size of the guest state, in bytes. */ + .total_sizeB = sizeof(VexGuestRISCV64State), + + /* Describe the stack pointer. */ + .offset_SP = offsetof(VexGuestRISCV64State, guest_x2), + .sizeof_SP = 8, + + /* Describe the frame pointer. */ + .offset_FP = offsetof(VexGuestRISCV64State, guest_x8), + .sizeof_FP = 8, + + /* Describe the instruction pointer. */ + .offset_IP = offsetof(VexGuestRISCV64State, guest_pc), + .sizeof_IP = 8, + + /* Describe any sections to be regarded by Memcheck as 'always-defined'. */ + .n_alwaysDefd = 6, + + .alwaysDefd = { + /* 0 */ ALWAYSDEFD(guest_x0), + /* 1 */ ALWAYSDEFD(guest_pc), + /* 2 */ ALWAYSDEFD(guest_EMNOTE), + /* 3 */ ALWAYSDEFD(guest_CMSTART), + /* 4 */ ALWAYSDEFD(guest_CMLEN), + /* 5 */ ALWAYSDEFD(guest_NRADDR), + }, +}; + +/*--------------------------------------------------------------------*/ +/*--- end guest_riscv64_helpers.c ---*/ +/*--------------------------------------------------------------------*/ diff --git a/VEX/priv/guest_riscv64_toIR.c b/VEX/priv/guest_riscv64_toIR.c new file mode 100644 index 0000000000..93ea5a173d --- /dev/null +++ b/VEX/priv/guest_riscv64_toIR.c @@ -0,0 +1,3511 @@ + +/*--------------------------------------------------------------------*/ +/*--- begin guest_riscv64_toIR.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* Translates riscv64 code to IR. */ + +/* "Special" instructions. + + This instruction decoder can decode four special instructions which mean + nothing natively (are no-ops as far as regs/mem are concerned) but have + meaning for supporting Valgrind. A special instruction is flagged by + a 16-byte preamble: + + 00305013 00d05013 03305013 03d05013 + (srli zero, zero, 3; srli zero, zero, 13 + srli zero, zero, 51; srli zero, zero, 61) + + Following that, one of the following 4 are allowed (standard interpretation + in parentheses): + + 00a56533 (or a0, a0, a0) a3 = client_request ( a4 ) + 00b5e5b3 (or a1, a1, a1) a3 = guest_NRADDR + 00c66633 (or a2, a2, a2) branch-and-link-to-noredir t0 + 00d6e6b3 (or a3, a3, a3) IR injection + + Any other bytes following the 16-byte preamble are illegal and constitute + a failure in instruction decoding. This all assumes that the preamble will + never occur except in specific code fragments designed for Valgrind to catch. +*/ + +#include "libvex_guest_riscv64.h" + +#include "guest_riscv64_defs.h" +#include "main_globals.h" +#include "main_util.h" + +/*------------------------------------------------------------*/ +/*--- Debugging output ---*/ +/*------------------------------------------------------------*/ + +#define DIP(format, args...) \ + do { \ + if (vex_traceflags & VEX_TRACE_FE) \ + vex_printf(format, ##args); \ + } while (0) + +#define DIS(buf, format, args...) \ + do { \ + if (vex_traceflags & VEX_TRACE_FE) \ + vex_sprintf(buf, format, ##args); \ + } while (0) + +/*------------------------------------------------------------*/ +/*--- Helper bits and pieces for deconstructing the ---*/ +/*--- riscv64 insn stream. ---*/ +/*------------------------------------------------------------*/ + +/* Do a little-endian load of a 32-bit word, regardless of the endianness of the + underlying host. */ +static inline UInt getUIntLittleEndianly(const UChar* p) +{ + UInt w = 0; + w = (w << 8) | p[3]; + w = (w << 8) | p[2]; + w = (w << 8) | p[1]; + w = (w << 8) | p[0]; + return w; +} + +/* Do read of an instruction, which can be 16-bit (compressed) or 32-bit in + size. */ +static inline UInt getInsn(const UChar* p) +{ + Bool is_compressed = (p[0] & 0x3) != 0x3; + UInt w = 0; + if (!is_compressed) { + w = (w << 8) | p[3]; + w = (w << 8) | p[2]; + } + w = (w << 8) | p[1]; + w = (w << 8) | p[0]; + return w; +} + +/* Produce _uint[_bMax:_bMin]. */ +#define SLICE_UInt(_uint, _bMax, _bMin) \ + ((((UInt)(_uint)) >> (_bMin)) & \ + (UInt)((1ULL << ((_bMax) - (_bMin) + 1)) - 1ULL)) + +/*------------------------------------------------------------*/ +/*--- Helpers for constructing IR. ---*/ +/*------------------------------------------------------------*/ + +/* Create an expression to produce a 64-bit constant. */ +static IRExpr* mkU64(ULong i) { return IRExpr_Const(IRConst_U64(i)); } + +/* Create an expression to produce a 32-bit constant. */ +static IRExpr* mkU32(UInt i) { return IRExpr_Const(IRConst_U32(i)); } + +/* Create an expression to produce an 8-bit constant. */ +static IRExpr* mkU8(UInt i) +{ + vassert(i < 256); + return IRExpr_Const(IRConst_U8((UChar)i)); +} + +/* Create an expression to read a temporary. */ +static IRExpr* mkexpr(IRTemp tmp) { return IRExpr_RdTmp(tmp); } + +/* Create an unary-operation expression. */ +static IRExpr* unop(IROp op, IRExpr* a) { return IRExpr_Unop(op, a); } + +/* Create a binary-operation expression. */ +static IRExpr* binop(IROp op, IRExpr* a1, IRExpr* a2) +{ + return IRExpr_Binop(op, a1, a2); +} + +/* Create a ternary-operation expression. */ +static IRExpr* triop(IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3) +{ + return IRExpr_Triop(op, a1, a2, a3); +} + +/* Create a quaternary-operation expression. */ +static IRExpr* qop(IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3, IRExpr* a4) +{ + return IRExpr_Qop(op, a1, a2, a3, a4); +} + +/* Create an expression to load a value from memory (in the little-endian + order). */ +static IRExpr* loadLE(IRType ty, IRExpr* addr) +{ + return IRExpr_Load(Iend_LE, ty, addr); +} + +/* Add a statement to the list held by irsb. */ +static void stmt(/*MOD*/ IRSB* irsb, IRStmt* st) { addStmtToIRSB(irsb, st); } + +/* Add a statement to assign a value to a temporary. */ +static void assign(/*MOD*/ IRSB* irsb, IRTemp dst, IRExpr* e) +{ + stmt(irsb, IRStmt_WrTmp(dst, e)); +} + +/* Generate a statement to store a value in memory (in the little-endian + order). */ +static void storeLE(/*MOD*/ IRSB* irsb, IRExpr* addr, IRExpr* data) +{ + stmt(irsb, IRStmt_Store(Iend_LE, addr, data)); +} + +/* Generate a new temporary of the given type. */ +static IRTemp newTemp(/*MOD*/ IRSB* irsb, IRType ty) +{ + vassert(isPlausibleIRType(ty)); + return newIRTemp(irsb->tyenv, ty); +} + +/* Sign-extend a 32/64-bit integer expression to 64 bits. */ +static IRExpr* widenSto64(IRType srcTy, IRExpr* e) +{ + switch (srcTy) { + case Ity_I64: + return e; + case Ity_I32: + return unop(Iop_32Sto64, e); + default: + vpanic("widenSto64(riscv64)"); + } +} + +/* Narrow a 64-bit integer expression to 32/64 bits. */ +static IRExpr* narrowFrom64(IRType dstTy, IRExpr* e) +{ + switch (dstTy) { + case Ity_I64: + return e; + case Ity_I32: + return unop(Iop_64to32, e); + default: + vpanic("narrowFrom64(riscv64)"); + } +} + +/*------------------------------------------------------------*/ +/*--- Offsets of various parts of the riscv64 guest state ---*/ +/*------------------------------------------------------------*/ + +#define OFFB_X0 offsetof(VexGuestRISCV64State, guest_x0) +#define OFFB_X1 offsetof(VexGuestRISCV64State, guest_x1) +#define OFFB_X2 offsetof(VexGuestRISCV64State, guest_x2) +#define OFFB_X3 offsetof(VexGuestRISCV64State, guest_x3) +#define OFFB_X4 offsetof(VexGuestRISCV64State, guest_x4) +#define OFFB_X5 offsetof(VexGuestRISCV64State, guest_x5) +#define OFFB_X6 offsetof(VexGuestRISCV64State, guest_x6) +#define OFFB_X7 offsetof(VexGuestRISCV64State, guest_x7) +#define OFFB_X8 offsetof(VexGuestRISCV64State, guest_x8) +#define OFFB_X9 offsetof(VexGuestRISCV64State, guest_x9) +#define OFFB_X10 offsetof(VexGuestRISCV64State, guest_x10) +#define OFFB_X11 offsetof(VexGuestRISCV64State, guest_x11) +#define OFFB_X12 offsetof(VexGuestRISCV64State, guest_x12) +#define OFFB_X13 offsetof(VexGuestRISCV64State, guest_x13) +#define OFFB_X14 offsetof(VexGuestRISCV64State, guest_x14) +#define OFFB_X15 offsetof(VexGuestRISCV64State, guest_x15) +#define OFFB_X16 offsetof(VexGuestRISCV64State, guest_x16) +#define OFFB_X17 offsetof(VexGuestRISCV64State, guest_x17) +#define OFFB_X18 offsetof(VexGuestRISCV64State, guest_x18) +#define OFFB_X19 offsetof(VexGuestRISCV64State, guest_x19) +#define OFFB_X20 offsetof(VexGuestRISCV64State, guest_x20) +#define OFFB_X21 offsetof(VexGuestRISCV64State, guest_x21) +#define OFFB_X22 offsetof(VexGuestRISCV64State, guest_x22) +#define OFFB_X23 offsetof(VexGuestRISCV64State, guest_x23) +#define OFFB_X24 offsetof(VexGuestRISCV64State, guest_x24) +#define OFFB_X25 offsetof(VexGuestRISCV64State, guest_x25) +#define OFFB_X26 offsetof(VexGuestRISCV64State, guest_x26) +#define OFFB_X27 offsetof(VexGuestRISCV64State, guest_x27) +#define OFFB_X28 offsetof(VexGuestRISCV64State, guest_x28) +#define OFFB_X29 offsetof(VexGuestRISCV64State, guest_x29) +#define OFFB_X30 offsetof(VexGuestRISCV64State, guest_x30) +#define OFFB_X31 offsetof(VexGuestRISCV64State, guest_x31) +#define OFFB_PC offsetof(VexGuestRISCV64State, guest_pc) + +#define OFFB_F0 offsetof(VexGuestRISCV64State, guest_f0) +#define OFFB_F1 offsetof(VexGuestRISCV64State, guest_f1) +#define OFFB_F2 offsetof(VexGuestRISCV64State, guest_f2) +#define OFFB_F3 offsetof(VexGuestRISCV64State, guest_f3) +#define OFFB_F4 offsetof(VexGuestRISCV64State, guest_f4) +#define OFFB_F5 offsetof(VexGuestRISCV64State, guest_f5) +#define OFFB_F6 offsetof(VexGuestRISCV64State, guest_f6) +#define OFFB_F7 offsetof(VexGuestRISCV64State, guest_f7) +#define OFFB_F8 offsetof(VexGuestRISCV64State, guest_f8) +#define OFFB_F9 offsetof(VexGuestRISCV64State, guest_f9) +#define OFFB_F10 offsetof(VexGuestRISCV64State, guest_f10) +#define OFFB_F11 offsetof(VexGuestRISCV64State, guest_f11) +#define OFFB_F12 offsetof(VexGuestRISCV64State, guest_f12) +#define OFFB_F13 offsetof(VexGuestRISCV64State, guest_f13) +#define OFFB_F14 offsetof(VexGuestRISCV64State, guest_f14) +#define OFFB_F15 offsetof(VexGuestRISCV64State, guest_f15) +#define OFFB_F16 offsetof(VexGuestRISCV64State, guest_f16) +#define OFFB_F17 offsetof(VexGuestRISCV64State, guest_f17) +#define OFFB_F18 offsetof(VexGuestRISCV64State, guest_f18) +#define OFFB_F19 offsetof(VexGuestRISCV64State, guest_f19) +#define OFFB_F20 offsetof(VexGuestRISCV64State, guest_f20) +#define OFFB_F21 offsetof(VexGuestRISCV64State, guest_f21) +#define OFFB_F22 offsetof(VexGuestRISCV64State, guest_f22) +#define OFFB_F23 offsetof(VexGuestRISCV64State, guest_f23) +#define OFFB_F24 offsetof(VexGuestRISCV64State, guest_f24) +#define OFFB_F25 offsetof(VexGuestRISCV64State, guest_f25) +#define OFFB_F26 offsetof(VexGuestRISCV64State, guest_f26) +#define OFFB_F27 offsetof(VexGuestRISCV64State, guest_f27) +#define OFFB_F28 offsetof(VexGuestRISCV64State, guest_f28) +#define OFFB_F29 offsetof(VexGuestRISCV64State, guest_f29) +#define OFFB_F30 offsetof(VexGuestRISCV64State, guest_f30) +#define OFFB_F31 offsetof(VexGuestRISCV64State, guest_f31) +#define OFFB_FCSR offsetof(VexGuestRISCV64State, guest_fcsr) + +#define OFFB_EMNOTE offsetof(VexGuestRISCV64State, guest_EMNOTE) +#define OFFB_CMSTART offsetof(VexGuestRISCV64State, guest_CMSTART) +#define OFFB_CMLEN offsetof(VexGuestRISCV64State, guest_CMLEN) +#define OFFB_NRADDR offsetof(VexGuestRISCV64State, guest_NRADDR) + +#define OFFB_LLSC_SIZE offsetof(VexGuestRISCV64State, guest_LLSC_SIZE) +#define OFFB_LLSC_ADDR offsetof(VexGuestRISCV64State, guest_LLSC_ADDR) +#define OFFB_LLSC_DATA offsetof(VexGuestRISCV64State, guest_LLSC_DATA) + +/*------------------------------------------------------------*/ +/*--- Integer registers ---*/ +/*------------------------------------------------------------*/ + +static Int offsetIReg64(UInt iregNo) +{ + switch (iregNo) { + case 0: + return OFFB_X0; + case 1: + return OFFB_X1; + case 2: + return OFFB_X2; + case 3: + return OFFB_X3; + case 4: + return OFFB_X4; + case 5: + return OFFB_X5; + case 6: + return OFFB_X6; + case 7: + return OFFB_X7; + case 8: + return OFFB_X8; + case 9: + return OFFB_X9; + case 10: + return OFFB_X10; + case 11: + return OFFB_X11; + case 12: + return OFFB_X12; + case 13: + return OFFB_X13; + case 14: + return OFFB_X14; + case 15: + return OFFB_X15; + case 16: + return OFFB_X16; + case 17: + return OFFB_X17; + case 18: + return OFFB_X18; + case 19: + return OFFB_X19; + case 20: + return OFFB_X20; + case 21: + return OFFB_X21; + case 22: + return OFFB_X22; + case 23: + return OFFB_X23; + case 24: + return OFFB_X24; + case 25: + return OFFB_X25; + case 26: + return OFFB_X26; + case 27: + return OFFB_X27; + case 28: + return OFFB_X28; + case 29: + return OFFB_X29; + case 30: + return OFFB_X30; + case 31: + return OFFB_X31; + default: + vassert(0); + } +} + +/* Obtain ABI name of a register. */ +static const HChar* nameIReg(UInt iregNo) +{ + vassert(iregNo < 32); + static const HChar* names[32] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", + "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", + "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; + return names[iregNo]; +} + +/* Read a 64-bit value from a guest integer register. */ +static IRExpr* getIReg64(UInt iregNo) +{ + vassert(iregNo < 32); + return IRExpr_Get(offsetIReg64(iregNo), Ity_I64); +} + +/* Write a 64-bit value into a guest integer register. */ +static void putIReg64(/*OUT*/ IRSB* irsb, UInt iregNo, /*IN*/ IRExpr* e) +{ + vassert(iregNo > 0 && iregNo < 32); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64); + stmt(irsb, IRStmt_Put(offsetIReg64(iregNo), e)); +} + +/* Read a 32-bit value from a guest integer register. */ +static IRExpr* getIReg32(UInt iregNo) +{ + vassert(iregNo < 32); + return unop(Iop_64to32, IRExpr_Get(offsetIReg64(iregNo), Ity_I64)); +} + +/* Write a 32-bit value into a guest integer register. */ +static void putIReg32(/*OUT*/ IRSB* irsb, UInt iregNo, /*IN*/ IRExpr* e) +{ + vassert(iregNo > 0 && iregNo < 32); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32); + stmt(irsb, IRStmt_Put(offsetIReg64(iregNo), unop(Iop_32Sto64, e))); +} + +/* Write an address into the guest pc. */ +static void putPC(/*OUT*/ IRSB* irsb, /*IN*/ IRExpr* e) +{ + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64); + stmt(irsb, IRStmt_Put(OFFB_PC, e)); +} + +/*------------------------------------------------------------*/ +/*--- Floating-point registers ---*/ +/*------------------------------------------------------------*/ + +static Int offsetFReg(UInt fregNo) +{ + switch (fregNo) { + case 0: + return OFFB_F0; + case 1: + return OFFB_F1; + case 2: + return OFFB_F2; + case 3: + return OFFB_F3; + case 4: + return OFFB_F4; + case 5: + return OFFB_F5; + case 6: + return OFFB_F6; + case 7: + return OFFB_F7; + case 8: + return OFFB_F8; + case 9: + return OFFB_F9; + case 10: + return OFFB_F10; + case 11: + return OFFB_F11; + case 12: + return OFFB_F12; + case 13: + return OFFB_F13; + case 14: + return OFFB_F14; + case 15: + return OFFB_F15; + case 16: + return OFFB_F16; + case 17: + return OFFB_F17; + case 18: + return OFFB_F18; + case 19: + return OFFB_F19; + case 20: + return OFFB_F20; + case 21: + return OFFB_F21; + case 22: + return OFFB_F22; + case 23: + return OFFB_F23; + case 24: + return OFFB_F24; + case 25: + return OFFB_F25; + case 26: + return OFFB_F26; + case 27: + return OFFB_F27; + case 28: + return OFFB_F28; + case 29: + return OFFB_F29; + case 30: + return OFFB_F30; + case 31: + return OFFB_F31; + default: + vassert(0); + } +} + +/* Obtain ABI name of a register. */ +static const HChar* nameFReg(UInt fregNo) +{ + vassert(fregNo < 32); + static const HChar* names[32] = { + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"}; + return names[fregNo]; +} + +/* Read a 64-bit value from a guest floating-point register. */ +static IRExpr* getFReg64(UInt fregNo) +{ + vassert(fregNo < 32); + return IRExpr_Get(offsetFReg(fregNo), Ity_F64); +} + +/* Write a 64-bit value into a guest floating-point register. */ +static void putFReg64(/*OUT*/ IRSB* irsb, UInt fregNo, /*IN*/ IRExpr* e) +{ + vassert(fregNo < 32); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64); + stmt(irsb, IRStmt_Put(offsetFReg(fregNo), e)); +} + +/* Read a 32-bit value from a guest floating-point register. */ +static IRExpr* getFReg32(UInt fregNo) +{ + vassert(fregNo < 32); + /* Note that the following access depends on the host being little-endian + which is checked in disInstr_RISCV64(). */ + /* TODO Check that the value is correctly NaN-boxed. If not then return + the 32-bit canonical qNaN, as mandated by the RISC-V ISA. */ + return IRExpr_Get(offsetFReg(fregNo), Ity_F32); +} + +/* Write a 32-bit value into a guest floating-point register. */ +static void putFReg32(/*OUT*/ IRSB* irsb, UInt fregNo, /*IN*/ IRExpr* e) +{ + vassert(fregNo < 32); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32); + /* Note that the following access depends on the host being little-endian + which is checked in disInstr_RISCV64(). */ + Int offset = offsetFReg(fregNo); + stmt(irsb, IRStmt_Put(offset, e)); + /* Write 1's in the upper bits of the target 64-bit register to create + a NaN-boxed value, as mandated by the RISC-V ISA. */ + stmt(irsb, IRStmt_Put(offset + 4, mkU32(0xffffffff))); + /* TODO Check that this works with Memcheck. */ +} + +/* Read a 32-bit value from the fcsr. */ +static IRExpr* getFCSR(void) { return IRExpr_Get(OFFB_FCSR, Ity_I32); } + +/* Write a 32-bit value into the fcsr. */ +static void putFCSR(/*OUT*/ IRSB* irsb, /*IN*/ IRExpr* e) +{ + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32); + stmt(irsb, IRStmt_Put(OFFB_FCSR, e)); +} + +/* Accumulate exception flags in fcsr. */ +static void accumulateFFLAGS(/*OUT*/ IRSB* irsb, /*IN*/ IRExpr* e) +{ + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32); + putFCSR(irsb, binop(Iop_Or32, getFCSR(), binop(Iop_And32, e, mkU32(0x1f)))); +} + +/* Generate IR to get hold of the rounding mode in both RISC-V and IR + formats. A floating-point operation can use either a static rounding mode + encoded in the instruction, or a dynamic rounding mode held in fcsr. Bind the + final result to the passed temporaries (which are allocated by the function). + */ +static void mk_get_rounding_mode(/*MOD*/ IRSB* irsb, + /*OUT*/ IRTemp* rm_RISCV, + /*OUT*/ IRTemp* rm_IR, + UInt inst_rm_RISCV) +{ + /* + rounding mode | RISC-V | IR + -------------------------------------------- + to nearest, ties to even | 000 | 0000 + to zero | 001 | 0011 + to +infinity | 010 | 0010 + to -infinity | 011 | 0001 + to nearest, ties away from 0 | 100 | 0100 + invalid | 101 | 1000 + invalid | 110 | 1000 + dynamic | 111 | 1000 + + The 'dynamic' value selects the mode from fcsr. Its value is valid when + encoded in the instruction but naturally invalid when found in fcsr. + + Static mode is known at the decode time and can be directly expressed by + a respective rounding mode IR constant. + + Dynamic mode requires a runtime mapping from the RISC-V to the IR mode. + It can be implemented using the following transformation: + t0 = fcsr_rm_RISCV - 20 + t1 = t0 >> 2 + t2 = fcsr_rm_RISCV + 3 + t3 = t2 ^ 3 + rm_IR = t1 & t3 + */ + *rm_RISCV = newTemp(irsb, Ity_I32); + *rm_IR = newTemp(irsb, Ity_I32); + switch (inst_rm_RISCV) { + case 0b000: + assign(irsb, *rm_RISCV, mkU32(0)); + assign(irsb, *rm_IR, mkU32(Irrm_NEAREST)); + break; + case 0b001: + assign(irsb, *rm_RISCV, mkU32(1)); + assign(irsb, *rm_IR, mkU32(Irrm_ZERO)); + break; + case 0b010: + assign(irsb, *rm_RISCV, mkU32(2)); + assign(irsb, *rm_IR, mkU32(Irrm_PosINF)); + break; + case 0b011: + assign(irsb, *rm_RISCV, mkU32(3)); + assign(irsb, *rm_IR, mkU32(Irrm_NegINF)); + break; + case 0b100: + assign(irsb, *rm_RISCV, mkU32(4)); + assign(irsb, *rm_IR, mkU32(Irrm_NEAREST_TIE_AWAY_0)); + break; + case 0b101: + assign(irsb, *rm_RISCV, mkU32(5)); + assign(irsb, *rm_IR, mkU32(Irrm_INVALID)); + break; + case 0b110: + assign(irsb, *rm_RISCV, mkU32(6)); + assign(irsb, *rm_IR, mkU32(Irrm_INVALID)); + break; + case 0b111: { + assign(irsb, *rm_RISCV, + binop(Iop_And32, binop(Iop_Shr32, getFCSR(), mkU8(5)), mkU32(7))); + IRTemp t0 = newTemp(irsb, Ity_I32); + assign(irsb, t0, binop(Iop_Sub32, mkexpr(*rm_RISCV), mkU32(20))); + IRTemp t1 = newTemp(irsb, Ity_I32); + assign(irsb, t1, binop(Iop_Shr32, mkexpr(t0), mkU8(2))); + IRTemp t2 = newTemp(irsb, Ity_I32); + assign(irsb, t2, binop(Iop_Add32, mkexpr(*rm_RISCV), mkU32(3))); + IRTemp t3 = newTemp(irsb, Ity_I32); + assign(irsb, t3, binop(Iop_Xor32, mkexpr(t2), mkU32(3))); + assign(irsb, *rm_IR, binop(Iop_And32, mkexpr(t1), mkexpr(t3))); + break; + } + default: + vassert(0); + } +} + +/*------------------------------------------------------------*/ +/*--- Name helpers ---*/ +/*------------------------------------------------------------*/ + +/* Obtain an acquire/release atomic-instruction suffix. */ +static const HChar* nameAqRlSuffix(UInt aqrl) +{ + switch (aqrl) { + case 0b00: + return ""; + case 0b01: + return ".rl"; + case 0b10: + return ".aq"; + case 0b11: + return ".aqrl"; + default: + vpanic("nameAqRlSuffix(riscv64)"); + } +} + +/* Obtain a control/status register name. */ +static const HChar* nameCSR(UInt csr) +{ + switch (csr) { + case 0x001: + return "fflags"; + case 0x002: + return "frm"; + case 0x003: + return "fcsr"; + default: + vpanic("nameCSR(riscv64)"); + } +} + +/* Obtain a floating-point rounding-mode operand string. */ +static const HChar* nameRMOperand(UInt rm) +{ + switch (rm) { + case 0b000: + return ", rne"; + case 0b001: + return ", rtz"; + case 0b010: + return ", rdn"; + case 0b011: + return ", rup"; + case 0b100: + return ", rmm"; + case 0b101: + return ", <invalid>"; + case 0b110: + return ", <invalid>"; + case 0b111: + return ""; /* dyn */ + default: + vpanic("nameRMOperand(riscv64)"); + } +} + +/*------------------------------------------------------------*/ +/*--- Disassemble a single instruction ---*/ +/*------------------------------------------------------------*/ + +/* A macro to fish bits out of 'insn' which is a local variable to all + disassembly functions. */ +#define INSN(_bMax, _bMin) SLICE_UInt(insn, (_bMax), (_bMin)) + +static Bool dis_RV64C(/*MB_OUT*/ DisResult* dres, + /*OUT*/ IRSB* irsb, + UInt insn, + Addr guest_pc_curr_instr, + Bool sigill_diag) +{ + vassert(INSN(1, 0) == 0b00 || INSN(1, 0) == 0b01 || INSN(1, 0) == 0b10); + + /* ---- RV64C compressed instruction set, quadrant 0 ----- */ + + /* ------------- c.addi4spn rd, nzuimm[9:2] -------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b000) { + UInt rd = INSN(4, 2) + 8; + UInt nzuimm9_2 = + INSN(10, 7) << 4 | INSN(12, 11) << 2 | INSN(5, 5) << 1 | INSN(6, 6); + if (nzuimm9_2 == 0) { + /* Invalid C.ADDI4SPN, fall through. */ + } else { + ULong uimm = nzuimm9_2 << 2; + putIReg64(irsb, rd, + binop(Iop_Add64, getIReg64(2 /*x2/sp*/), mkU64(uimm))); + DIP("c.addi4spn %s, %llu\n", nameIReg(rd), uimm); + return True; + } + } + + /* -------------- c.fld rd, uimm[7:3](rs1) --------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b001) { + UInt rd = INSN(4, 2) + 8; + UInt rs1 = INSN(9, 7) + 8; + UInt uimm7_3 = INSN(6, 5) << 3 | INSN(12, 10); + ULong uimm = uimm7_3 << 3; + putFReg64(irsb, rd, + loadLE(Ity_F64, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm)))); + DIP("c.fld %s, %llu(%s)\n", nameFReg(rd), uimm, nameIReg(rs1)); + return True; + } + + /* --------------- c.lw rd, uimm[6:2](rs1) --------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b010) { + UInt rd = INSN(4, 2) + 8; + UInt rs1 = INSN(9, 7) + 8; + UInt uimm6_2 = INSN(5, 5) << 4 | INSN(12, 10) << 1 | INSN(6, 6); + ULong uimm = uimm6_2 << 2; + putIReg64( + irsb, rd, + unop(Iop_32Sto64, + loadLE(Ity_I32, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm))))); + DIP("c.lw %s, %llu(%s)\n", nameIReg(rd), uimm, nameIReg(rs1)); + return True; + } + + /* --------------- c.ld rd, uimm[7:3](rs1) --------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b011) { + UInt rd = INSN(4, 2) + 8; + UInt rs1 = INSN(9, 7) + 8; + UInt uimm7_3 = INSN(6, 5) << 3 | INSN(12, 10); + ULong uimm = uimm7_3 << 3; + putIReg64(irsb, rd, + loadLE(Ity_I64, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm)))); + DIP("c.ld %s, %llu(%s)\n", nameIReg(rd), uimm, nameIReg(rs1)); + return True; + } + + /* -------------- c.fsd rs2, uimm[7:3](rs1) -------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b101) { + UInt rs1 = INSN(9, 7) + 8; + UInt rs2 = INSN(4, 2) + 8; + UInt uimm7_3 = INSN(6, 5) << 3 | INSN(12, 10); + ULong uimm = uimm7_3 << 3; + storeLE(irsb, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm)), + getFReg64(rs2)); + DIP("c.fsd %s, %llu(%s)\n", nameFReg(rs2), uimm, nameIReg(rs1)); + return True; + } + + /* -------------- c.sw rs2, uimm[6:2](rs1) --------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b110) { + UInt rs1 = INSN(9, 7) + 8; + UInt rs2 = INSN(4, 2) + 8; + UInt uimm6_2 = INSN(5, 5) << 4 | INSN(12, 10) << 1 | INSN(6, 6); + ULong uimm = uimm6_2 << 2; + storeLE(irsb, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm)), + unop(Iop_64to32, getIReg64(rs2))); + DIP("c.sw %s, %llu(%s)\n", nameIReg(rs2), uimm, nameIReg(rs1)); + return True; + } + + /* -------------- c.sd rs2, uimm[7:3](rs1) --------------- */ + if (INSN(1, 0) == 0b00 && INSN(15, 13) == 0b111) { + UInt rs1 = INSN(9, 7) + 8; + UInt rs2 = INSN(4, 2) + 8; + UInt uimm7_3 = INSN(6, 5) << 3 | INSN(12, 10); + ULong uimm = uimm7_3 << 3; + storeLE(irsb, binop(Iop_Add64, getIReg64(rs1), mkU64(uimm)), + getIReg64(rs2)); + DIP("c.sd %s, %llu(%s)\n", nameIReg(rs2), uimm, nameIReg(rs1)); + return True; + } + + /* ---- RV64C compressed instruction set, quadrant 1 ----- */ + + /* ------------------------ c.nop ------------------------ */ + if (INSN(15, 0) == 0b0000000000000001) { + DIP("c.nop\n"); + return True; + } + + /* -------------- c.addi rd_rs1, nzimm[5:0] -------------- */ + if (INSN(1, 0) == 0b01 && INSN(15, 13) == 0b000) { + UInt rd_rs1 = INSN(11, 7); + UInt nzimm5_0 = INSN(12, 12) << 5 | INSN(6, 2); + if (rd_rs1 == 0 || nzimm5_0 == 0) { + /* Invalid C.ADDI, fall through. */ + } else { + ULong simm = vex_sx_to_64(nzimm5_0, 6); + putIReg64(irsb, rd_rs1, + binop(Iop_Add64, getIReg64(rd_rs1), mkU64(simm))); + DIP("c.addi %s, %lld\n", nameIReg(rd_rs1), (Long)simm); + return True; + } + } + + /* -------------- c.addiw rd_rs1, imm[5:0] --------------- */ + if (INSN(1, 0) == 0b01 && INSN(15, 13) == 0b001) { + UInt rd_rs1 = INSN(11, 7); + UInt imm5_0 = INSN(12, 12) << 5 | INSN(6, 2); + if (rd_rs1 == 0) { + /* Invalid C.ADDIW, fall through. */ + } else { + UInt simm = (UInt)vex_sx_to_64(imm5_0, 6); + putIReg32(irsb, rd_rs1, + binop(Iop_Add32, getIReg32(rd_rs1), mkU32(simm))); + DIP("c.addiw %s, %d\n", nameIReg(rd_rs1), (Int)simm); + return True; + } + } + + /* ------------------ c.li rd, imm[5:0] ------------------ */ + if (INSN(1, 0) == 0b01 && INSN(15, 13) == 0b010) { + UInt rd = INSN(11, 7); + UInt imm5_0 = INSN(12, 12) << 5 | INSN(6, 2); + if (rd == 0) { + /* Invalid C.LI, fall through. */ + } else { + ULong simm = vex_sx_to_64(imm5_0, 6); + putIReg64(irsb, rd, mkU64(simm)); + DIP("c.li %s, %lld\n", nameIReg(rd), (Long)simm); + return True; + } + } + + /* ---------------- c.addi16sp nzimm[9:4] ---------------- */ + if (INSN(1, 0) == 0b01 && INSN(15, 13) == 0b011) { + UInt rd_rs1 = INSN(11, 7); + UInt nzimm9_4 = INSN(12, 12) << 5 | INSN(4, 3) << 3 | INSN(5, 5) << 2 | + INSN(2, 2) << 1 | INSN(6, 6); + if (rd_rs1 != 2 || nzimm9_4 == 0) { + /* Invalid C.ADDI16SP, fall through. */ + } else { + ULong simm = vex_sx_to_64(nzimm9_4 << 4, 10); + putIReg64(irsb, rd_rs1, + binop(Iop_Add64, getIReg64(rd_rs1), mkU64(simm))); + DIP("c.addi16sp %lld\n", (Long)sim... [truncated message content] |
From: Mark W. <ma...@so...> - 2025-02-25 16:52:19
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=949abd0472161a7fc0aa5e869f89b533793f0948 commit 949abd0472161a7fc0aa5e869f89b533793f0948 Author: Petr Pavlu <pet...@da...> Date: Tue Apr 11 19:30:42 2023 +0000 riscv64: Add initial support: new port-specific Valgrind files The following people contributed to the initial RISC-V support: Petr Pavlu <pet...@da...> Xeonacid <h.d...@gm...> laokz <la...@fo...> Chelsea E. Manning <me...@xy...> zhaomingxin <zha...@al...> Jojo R <rj...@li...> Some integration fixes were added by Mark Wielaard <ma...@kl...> - Remove POST handler from sys_close - Define VKI_O_DIRECT in vki-riscv64-linux.h - Wrap riscv64-linux mlock2 - Add POST handler for sys_readlinkat https://bugs.kde.org/show_bug.cgi?id=493507 Diff: --- README.riscv64 | 45 ++ coregrind/m_dispatch/dispatch-riscv64-linux.S | 298 ++++++++++ coregrind/m_gdbserver/riscv64-cpu-valgrind-s1.xml | 43 ++ coregrind/m_gdbserver/riscv64-cpu-valgrind-s2.xml | 43 ++ coregrind/m_gdbserver/riscv64-cpu.xml | 47 ++ coregrind/m_gdbserver/riscv64-fpu-valgrind-s1.xml | 47 ++ coregrind/m_gdbserver/riscv64-fpu-valgrind-s2.xml | 47 ++ coregrind/m_gdbserver/riscv64-fpu.xml | 56 ++ coregrind/m_gdbserver/riscv64-linux-valgrind.xml | 21 + coregrind/m_gdbserver/riscv64-linux.xml | 17 + coregrind/m_gdbserver/valgrind-low-riscv64.c | 287 ++++++++++ coregrind/m_sigframe/sigframe-riscv64-linux.c | 422 ++++++++++++++ coregrind/m_syswrap/syscall-riscv64-linux.S | 198 +++++++ coregrind/m_syswrap/syswrap-riscv64-linux.c | 608 +++++++++++++++++++++ docs/internals/qemu-riscv64-linux-HOWTO.txt | 46 ++ include/vki/vki-posixtypes-riscv64-linux.h | 66 +++ include/vki/vki-riscv64-linux.h | 635 ++++++++++++++++++++++ include/vki/vki-scnums-riscv64-linux.h | 329 +++++++++++ 18 files changed, 3255 insertions(+) diff --git a/README.riscv64 b/README.riscv64 new file mode 100644 index 0000000000..04f2bc9572 --- /dev/null +++ b/README.riscv64 @@ -0,0 +1,45 @@ + +Status +~~~~~~ + +The RISC-V port targets the 64-bit RISC-V architecture and the Linux operating +system. The port has been tested to work on real hardware and under QEMU. + +The following ISA base and extensions are currently supported: + +| Name | Description | #Instrs | Notes | +| ------------ | --------------------------------- | ------- | -------- | +| RV64I | Base instruction set | 52/52 | | +| RV64M | Integer multiplication & division | 12/13 | (1) | +| RV64A | Atomic | 22/22 | (2) | +| RV64F | Single-precision floating-point | 30/30 | (3) | +| RV64D | Double-precision floating-point | 32/32 | | +| RV64Zicsr | Control & status register | 2/6 | (4), (5) | +| RV64Zifencei | Instruction-fetch fence | 0/1 | (6) | +| RV64C | Compressed | 37/37 | | + +Notes: +(1) MULHSU is not recognized. +(2) LR and SC use the VEX "fallback" method which suffers from the ABA problem. +(3) Operations do not check if the input operands are correctly NaN-boxed. +(4) CSRRC, CSRRWI, CSRRSI and CSRRCI are not recognized. +(5) Only registers fflags, frm and fcsr are accepted. +(6) FENCE.I is not recognized. + + +Implementation tidying-up/TODO notes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* Implement a proper "non-fallback" method for LR and SC instructions. +* Add a check for correct NaN-boxing of 32-bit floating-point operands. +* Optimize instruction selection, in particular make more use of <instr>i + variants. +* Optimize handling of floating-point exceptions. Avoid helpers and calculate + exception flags using the same instruction which produced an actual result. +* Review register usage by the codegen. +* Avoid re-use of Intel-constants CFIC_IA_SPREL and CFIC_IA_BPREL. Generalize + them for all architectures or introduce same CFIC_RISCV64_ variants. +* Get rid of the typedef of vki_modify_ldt_t in include/vki/vki-riscv64-linux.h. +* Review if setup_client_stack() should expose AT_SYSINFO_EHDR to clients. +* Make sure that the final exit sequence in run_a_thread_NORETURN() is not racy + in regards to accessing the thread state. diff --git a/coregrind/m_dispatch/dispatch-riscv64-linux.S b/coregrind/m_dispatch/dispatch-riscv64-linux.S new file mode 100644 index 0000000000..c4941e4573 --- /dev/null +++ b/coregrind/m_dispatch/dispatch-riscv64-linux.S @@ -0,0 +1,298 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core dispatch loop, for jumping to a code address. ---*/ +/*--- dispatch-riscv64-linux.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_riscv64_linux) + +#include "pub_core_dispatch_asm.h" +#include "pub_core_transtab_asm.h" +#include "libvex_guest_offsets.h" + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- The dispatch loop. VG_(disp_run_translations) is ---*/ +/*--- used to run all translations, ---*/ +/*--- including no-redir ones. ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/*----------------------------------------------------*/ +/*--- Entry and preamble (set everything up) ---*/ +/*----------------------------------------------------*/ + +/* signature: +void VG_(disp_run_translations)( UWord* two_words, + void* guest_state, + Addr host_addr ); +*/ +.text +.global VG_(disp_run_translations) +VG_(disp_run_translations): + /* a0 holds two_words + a1 holds guest_state + a2 holds host_addr + */ + /* Push the callee-saved registers. Note this sequence maintains + 16-alignment of sp. Also save a0 since it will be needed in the + postamble. */ + addi sp, sp, -112 + sd ra, 104(sp) + sd s0, 96(sp) + sd s1, 88(sp) + sd s2, 80(sp) + sd s3, 72(sp) + sd s4, 64(sp) + sd s5, 56(sp) + sd s6, 48(sp) + sd s7, 40(sp) + sd s8, 32(sp) + sd s9, 24(sp) + sd s10, 16(sp) + sd s11, 8(sp) + sd a0, 0(sp) + + /* Set up the guest state pointer. */ + li t0, 2048 + add s0, a1, t0 + + /* and jump into the code cache. Chained translations in the code cache + run, until for whatever reason, they can't continue. When that + happens, the translation in question will jump (or call) to one of + the continuation points VG_(cp_...) below. */ + jr a2 + /* NOTREACHED */ + +/*----------------------------------------------------*/ +/*--- Postamble and exit. ---*/ +/*----------------------------------------------------*/ + +postamble: + /* At this point, t0 and t1 contain two words to be returned to the + caller. t0 holds a TRC value, and t1 optionally may hold another + word (for CHAIN_ME exits, the address of the place to patch.) */ + + /* Restore int regs, including importantly a0 (two_words). */ + ld ra, 104(sp) + ld s0, 96(sp) + ld s1, 88(sp) + ld s2, 80(sp) + ld s3, 72(sp) + ld s4, 64(sp) + ld s5, 56(sp) + ld s6, 48(sp) + ld s7, 40(sp) + ld s8, 32(sp) + ld s9, 24(sp) + ld s10, 16(sp) + ld s11, 8(sp) + ld a0, 0(sp) + addi sp, sp, 112 + + /* Stash return values. */ + sd t0, 0(a0) + sd t1, 8(a0) + ret + +/*----------------------------------------------------*/ +/*--- Continuation points ---*/ +/*----------------------------------------------------*/ + +/* ------ Chain me to slow entry point ------ */ +.global VG_(disp_cp_chain_me_to_slowEP) +VG_(disp_cp_chain_me_to_slowEP): + /* We got called. The return address indicates where the patching needs + to happen. Collect the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA). */ + li t0, VG_TRC_CHAIN_ME_TO_SLOW_EP + mv t1, ra + /* 4 = lui t0, disp_cp_chain_me_to_slowEP[47:28]' + 4 = addiw t0, t0, disp_cp_chain_me_to_slowEP[27:16]' + 2 = c.slli t0, 12 + 4 = addi t0, t0, disp_cp_chain_me_to_slowEP[15:4]' + 2 = c.slli t0, 4 + 2 = c.addi t0, disp_cp_chain_me_to_slowEP[3:0]' + 2 = c.jalr 0(t0) + */ + addi t1, t1, -(4+4+2+4+2+2+2) + j postamble + +/* ------ Chain me to fast entry point ------ */ +.global VG_(disp_cp_chain_me_to_fastEP) +VG_(disp_cp_chain_me_to_fastEP): + /* We got called. The return address indicates where the patching needs + to happen. Collect the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA). */ + li t0, VG_TRC_CHAIN_ME_TO_FAST_EP + mv t1, ra + /* 4 = lui t0, disp_cp_chain_me_to_fastEP[47:28]' + 4 = addiw t0, t0, disp_cp_chain_me_to_fastEP[27:16]' + 2 = c.slli t0, 12 + 4 = addi t0, t0, disp_cp_chain_me_to_fastEP[15:4]' + 2 = c.slli t0, 4 + 2 = c.addi t0, disp_cp_chain_me_to_fastEP[3:0]' + 2 = c.jalr 0(t0) + */ + addi t1, t1, -(4+4+2+4+2+2+2) + j postamble + +/* ------ Indirect but boring jump ------ */ +.global VG_(disp_cp_xindir) +VG_(disp_cp_xindir): + /* Where are we going? */ + ld t0, OFFSET_riscv64_pc-2048(s0) + + /* Stats only. */ + lw t1, VG_(stats__n_xIndirs_32) + addi t1, t1, 1 + sw t1, VG_(stats__n_xIndirs_32), t2 + + /* LIVE: s0 (guest state ptr), t0 (guest address to go to). + We use 6 temporaries: + t6 (to point at the relevant FastCacheSet), + t1, t2, t3 (scratch, for swapping entries within a set) + t4, t5 (other scratch) */ + + /* Try a fast lookup in the translation cache. This is pretty much + a handcoded version of VG_(lookupInFastCache). */ + + /* Compute t6 = VG_TT_FAST_HASH(guest). */ + srli t6, t0, 1 /* g2 = guest >> 1 */ + srli t4, t6, VG_TT_FAST_BITS /* g2 >> VG_TT_FAST_BITS */ + xor t6, t4, t6 /* (g2 >> VG_TT_FAST_BITS) ^ g2 */ + li t4, VG_TT_FAST_MASK /* VG_TT_FAST_MASK */ + and t6, t6, t4 /* setNo */ + + /* Compute t6 = &VG_(tt_fast)[t6]. */ + la t4, VG_(tt_fast) /* &VG_(tt_fast)[0] */ + slli t6, t6, VG_FAST_CACHE_SET_BITS + add t6, t4, t6 /* &VG_(tt_fast)[setNo] */ + + /* LIVE: s0 (guest state ptr), t0 (guest addr), t6 (cache set). */ + /* Try way 0. */ + ld t4, FCS_g0(t6) /* t4 = .guest0 */ + bne t4, t0, 1f /* cmp against .guest0 */ + /* Hit at way 0. */ + /* Go to .host0. */ + ld t5, FCS_h0(t6) /* t5 = .host0 */ + jr t5 + /*NOTREACHED*/ + +1: /* Try way 1. */ + ld t4, FCS_g1(t6) + bne t4, t0, 2f /* cmp against .guest1 */ + /* Hit at way 1; swap upwards. */ + ld t1, FCS_g0(t6) /* t1 = old .guest0 */ + ld t2, FCS_h0(t6) /* t2 = old .host0 */ + ld t3, FCS_h1(t6) /* t3 = old .host1 */ + sd t0, FCS_g0(t6) /* new .guest0 = guest */ + sd t3, FCS_h0(t6) /* new .host0 = old .host1 */ + sd t1, FCS_g1(t6) /* new .guest1 = old .guest0 */ + sd t2, FCS_h1(t6) /* new .host1 = old .host0 */ + /* Stats only. */ + lw t4, VG_(stats__n_xIndir_hits1_32) + addi t4, t4, 1 + sw t4, VG_(stats__n_xIndir_hits1_32), t5 + /* Go to old .host1 a.k.a. new .host0. */ + jr t3 + /*NOTREACHED*/ + +2: /* Try way 2. */ + ld t4, FCS_g2(t6) + bne t4, t0, 3f /* cmp against .guest2 */ + /* Hit at way 2; swap upwards. */ + ld t1, FCS_g1(t6) + ld t2, FCS_h1(t6) + ld t3, FCS_h2(t6) + sd t0, FCS_g1(t6) + sd t3, FCS_h1(t6) + sd t1, FCS_g2(t6) + sd t2, FCS_h2(t6) + /* Stats only. */ + lw t4, VG_(stats__n_xIndir_hits2_32) + addi t4, t4, 1 + sw t4, VG_(stats__n_xIndir_hits2_32), t5 + /* Go to old .host2 a.k.a. new .host1. */ + jr t3 + /*NOTREACHED*/ + +3: /* Try way 3. */ + ld t4, FCS_g3(t6) + bne t4, t0, 4f /* cmp against .guest3 */ + /* Hit at way 3; swap upwards. */ + ld t1, FCS_g2(t6) + ld t2, FCS_h2(t6) + ld t3, FCS_h3(t6) + sd t0, FCS_g2(t6) + sd t3, FCS_h2(t6) + sd t1, FCS_g3(t6) + sd t2, FCS_h3(t6) + /* Stats only. */ + lw t4, VG_(stats__n_xIndir_hits3_32) + addi t4, t4, 1 + sw t4, VG_(stats__n_xIndir_hits3_32), t5 + /* Go to old .host3 a.k.a. new .host2. */ + jr t3 + /*NOTREACHED*/ + +4: /* Fast lookup failed. */ + lw t4, VG_(stats__n_xIndir_misses_32) + addi t4, t4, 1 + sw t4, VG_(stats__n_xIndir_misses_32), t5 + + li t0, VG_TRC_INNER_FASTMISS + li t1, 0 + j postamble + +/* ------ Assisted jump ------ */ +.global VG_(disp_cp_xassisted) +VG_(disp_cp_xassisted): + /* s0 contains the TRC. */ + mv t0, s0 + li t1, 0 + j postamble + +/* ------ Event check failed ------ */ +.global VG_(disp_cp_evcheck_fail) +VG_(disp_cp_evcheck_fail): + li t0, VG_TRC_INNER_COUNTERZERO + li t1, 0 + j postamble + +.size VG_(disp_run_translations), .-VG_(disp_run_translations) + +#endif // defined(VGP_riscv64_linux) + +/* Let the linker know we don't need an executable stack */ +MARK_STACK_NO_EXEC + +/*--------------------------------------------------------------------*/ +/*--- end dispatch-riscv64-linux.S ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_gdbserver/riscv64-cpu-valgrind-s1.xml b/coregrind/m_gdbserver/riscv64-cpu-valgrind-s1.xml new file mode 100644 index 0000000000..22c7dd0384 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-cpu-valgrind-s1.xml @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.cpu.valgrind.s1"> + <reg name="zeros1" bitsize="64" type="int" regnum="69"/> + <reg name="ras1" bitsize="64" type="int"/> + <reg name="sps1" bitsize="64" type="int"/> + <reg name="gps1" bitsize="64" type="int"/> + <reg name="tps1" bitsize="64" type="int"/> + <reg name="t0s1" bitsize="64" type="int"/> + <reg name="t1s1" bitsize="64" type="int"/> + <reg name="t2s1" bitsize="64" type="int"/> + <reg name="fps1" bitsize="64" type="int"/> + <reg name="s1s1" bitsize="64" type="int"/> + <reg name="a0s1" bitsize="64" type="int"/> + <reg name="a1s1" bitsize="64" type="int"/> + <reg name="a2s1" bitsize="64" type="int"/> + <reg name="a3s1" bitsize="64" type="int"/> + <reg name="a4s1" bitsize="64" type="int"/> + <reg name="a5s1" bitsize="64" type="int"/> + <reg name="a6s1" bitsize="64" type="int"/> + <reg name="a7s1" bitsize="64" type="int"/> + <reg name="s2s1" bitsize="64" type="int"/> + <reg name="s3s1" bitsize="64" type="int"/> + <reg name="s4s1" bitsize="64" type="int"/> + <reg name="s5s1" bitsize="64" type="int"/> + <reg name="s6s1" bitsize="64" type="int"/> + <reg name="s7s1" bitsize="64" type="int"/> + <reg name="s8s1" bitsize="64" type="int"/> + <reg name="s9s1" bitsize="64" type="int"/> + <reg name="s10s1" bitsize="64" type="int"/> + <reg name="s11s1" bitsize="64" type="int"/> + <reg name="t3s1" bitsize="64" type="int"/> + <reg name="t4s1" bitsize="64" type="int"/> + <reg name="t5s1" bitsize="64" type="int"/> + <reg name="t6s1" bitsize="64" type="int"/> + <reg name="pcs1" bitsize="64" type="int"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-cpu-valgrind-s2.xml b/coregrind/m_gdbserver/riscv64-cpu-valgrind-s2.xml new file mode 100644 index 0000000000..095a992fc1 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-cpu-valgrind-s2.xml @@ -0,0 +1,43 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.cpu.valgrind.s2"> + <reg name="zeros2" bitsize="64" type="int" regnum="138"/> + <reg name="ras2" bitsize="64" type="int"/> + <reg name="sps2" bitsize="64" type="int"/> + <reg name="gps2" bitsize="64" type="int"/> + <reg name="tps2" bitsize="64" type="int"/> + <reg name="t0s2" bitsize="64" type="int"/> + <reg name="t1s2" bitsize="64" type="int"/> + <reg name="t2s2" bitsize="64" type="int"/> + <reg name="fps2" bitsize="64" type="int"/> + <reg name="s1s2" bitsize="64" type="int"/> + <reg name="a0s2" bitsize="64" type="int"/> + <reg name="a1s2" bitsize="64" type="int"/> + <reg name="a2s2" bitsize="64" type="int"/> + <reg name="a3s2" bitsize="64" type="int"/> + <reg name="a4s2" bitsize="64" type="int"/> + <reg name="a5s2" bitsize="64" type="int"/> + <reg name="a6s2" bitsize="64" type="int"/> + <reg name="a7s2" bitsize="64" type="int"/> + <reg name="s2s2" bitsize="64" type="int"/> + <reg name="s3s2" bitsize="64" type="int"/> + <reg name="s4s2" bitsize="64" type="int"/> + <reg name="s5s2" bitsize="64" type="int"/> + <reg name="s6s2" bitsize="64" type="int"/> + <reg name="s7s2" bitsize="64" type="int"/> + <reg name="s8s2" bitsize="64" type="int"/> + <reg name="s9s2" bitsize="64" type="int"/> + <reg name="s10s2" bitsize="64" type="int"/> + <reg name="s11s2" bitsize="64" type="int"/> + <reg name="t3s2" bitsize="64" type="int"/> + <reg name="t4s2" bitsize="64" type="int"/> + <reg name="t5s2" bitsize="64" type="int"/> + <reg name="t6s2" bitsize="64" type="int"/> + <reg name="pcs2" bitsize="64" type="int"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-cpu.xml b/coregrind/m_gdbserver/riscv64-cpu.xml new file mode 100644 index 0000000000..2d31a6e199 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-cpu.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!-- Register numbers are hard-coded in order to maintain backward + compatibility with older versions of tools that didn't use xml + register descriptions. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.cpu"> + <reg name="zero" bitsize="64" type="int" regnum="0"/> + <reg name="ra" bitsize="64" type="code_ptr"/> + <reg name="sp" bitsize="64" type="data_ptr"/> + <reg name="gp" bitsize="64" type="data_ptr"/> + <reg name="tp" bitsize="64" type="data_ptr"/> + <reg name="t0" bitsize="64" type="int"/> + <reg name="t1" bitsize="64" type="int"/> + <reg name="t2" bitsize="64" type="int"/> + <reg name="fp" bitsize="64" type="data_ptr"/> + <reg name="s1" bitsize="64" type="int"/> + <reg name="a0" bitsize="64" type="int"/> + <reg name="a1" bitsize="64" type="int"/> + <reg name="a2" bitsize="64" type="int"/> + <reg name="a3" bitsize="64" type="int"/> + <reg name="a4" bitsize="64" type="int"/> + <reg name="a5" bitsize="64" type="int"/> + <reg name="a6" bitsize="64" type="int"/> + <reg name="a7" bitsize="64" type="int"/> + <reg name="s2" bitsize="64" type="int"/> + <reg name="s3" bitsize="64" type="int"/> + <reg name="s4" bitsize="64" type="int"/> + <reg name="s5" bitsize="64" type="int"/> + <reg name="s6" bitsize="64" type="int"/> + <reg name="s7" bitsize="64" type="int"/> + <reg name="s8" bitsize="64" type="int"/> + <reg name="s9" bitsize="64" type="int"/> + <reg name="s10" bitsize="64" type="int"/> + <reg name="s11" bitsize="64" type="int"/> + <reg name="t3" bitsize="64" type="int"/> + <reg name="t4" bitsize="64" type="int"/> + <reg name="t5" bitsize="64" type="int"/> + <reg name="t6" bitsize="64" type="int"/> + <reg name="pc" bitsize="64" type="code_ptr"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-fpu-valgrind-s1.xml b/coregrind/m_gdbserver/riscv64-fpu-valgrind-s1.xml new file mode 100644 index 0000000000..263a3fffbf --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-fpu-valgrind-s1.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.fpu.valgrind.s1"> + + <reg name="ft0s1" bitsize="64" type="int" regnum="102"/> + <reg name="ft1s1" bitsize="64" type="int"/> + <reg name="ft2s1" bitsize="64" type="int"/> + <reg name="ft3s1" bitsize="64" type="int"/> + <reg name="ft4s1" bitsize="64" type="int"/> + <reg name="ft5s1" bitsize="64" type="int"/> + <reg name="ft6s1" bitsize="64" type="int"/> + <reg name="ft7s1" bitsize="64" type="int"/> + <reg name="fs0s1" bitsize="64" type="int"/> + <reg name="fs1s1" bitsize="64" type="int"/> + <reg name="fa0s1" bitsize="64" type="int"/> + <reg name="fa1s1" bitsize="64" type="int"/> + <reg name="fa2s1" bitsize="64" type="int"/> + <reg name="fa3s1" bitsize="64" type="int"/> + <reg name="fa4s1" bitsize="64" type="int"/> + <reg name="fa5s1" bitsize="64" type="int"/> + <reg name="fa6s1" bitsize="64" type="int"/> + <reg name="fa7s1" bitsize="64" type="int"/> + <reg name="fs2s1" bitsize="64" type="int"/> + <reg name="fs3s1" bitsize="64" type="int"/> + <reg name="fs4s1" bitsize="64" type="int"/> + <reg name="fs5s1" bitsize="64" type="int"/> + <reg name="fs6s1" bitsize="64" type="int"/> + <reg name="fs7s1" bitsize="64" type="int"/> + <reg name="fs8s1" bitsize="64" type="int"/> + <reg name="fs9s1" bitsize="64" type="int"/> + <reg name="fs10s1" bitsize="64" type="int"/> + <reg name="fs11s1" bitsize="64" type="int"/> + <reg name="ft8s1" bitsize="64" type="int"/> + <reg name="ft9s1" bitsize="64" type="int"/> + <reg name="ft10s1" bitsize="64" type="int"/> + <reg name="ft11s1" bitsize="64" type="int"/> + + <reg name="fflagss1" bitsize="32" type="int" regnum="135"/> + <reg name="frms1" bitsize="32" type="int"/> + <reg name="fcsrs1" bitsize="32" type="int"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-fpu-valgrind-s2.xml b/coregrind/m_gdbserver/riscv64-fpu-valgrind-s2.xml new file mode 100644 index 0000000000..1992c03f21 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-fpu-valgrind-s2.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.fpu.valgrind.s2"> + + <reg name="ft0s2" bitsize="64" type="int" regnum="171"/> + <reg name="ft1s2" bitsize="64" type="int"/> + <reg name="ft2s2" bitsize="64" type="int"/> + <reg name="ft3s2" bitsize="64" type="int"/> + <reg name="ft4s2" bitsize="64" type="int"/> + <reg name="ft5s2" bitsize="64" type="int"/> + <reg name="ft6s2" bitsize="64" type="int"/> + <reg name="ft7s2" bitsize="64" type="int"/> + <reg name="fs0s2" bitsize="64" type="int"/> + <reg name="fs1s2" bitsize="64" type="int"/> + <reg name="fa0s2" bitsize="64" type="int"/> + <reg name="fa1s2" bitsize="64" type="int"/> + <reg name="fa2s2" bitsize="64" type="int"/> + <reg name="fa3s2" bitsize="64" type="int"/> + <reg name="fa4s2" bitsize="64" type="int"/> + <reg name="fa5s2" bitsize="64" type="int"/> + <reg name="fa6s2" bitsize="64" type="int"/> + <reg name="fa7s2" bitsize="64" type="int"/> + <reg name="fs2s2" bitsize="64" type="int"/> + <reg name="fs3s2" bitsize="64" type="int"/> + <reg name="fs4s2" bitsize="64" type="int"/> + <reg name="fs5s2" bitsize="64" type="int"/> + <reg name="fs6s2" bitsize="64" type="int"/> + <reg name="fs7s2" bitsize="64" type="int"/> + <reg name="fs8s2" bitsize="64" type="int"/> + <reg name="fs9s2" bitsize="64" type="int"/> + <reg name="fs10s2" bitsize="64" type="int"/> + <reg name="fs11s2" bitsize="64" type="int"/> + <reg name="ft8s2" bitsize="64" type="int"/> + <reg name="ft9s2" bitsize="64" type="int"/> + <reg name="ft10s2" bitsize="64" type="int"/> + <reg name="ft11s2" bitsize="64" type="int"/> + + <reg name="fflagss2" bitsize="32" type="int" regnum="204"/> + <reg name="frms2" bitsize="32" type="int"/> + <reg name="fcsrs2" bitsize="32" type="int"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-fpu.xml b/coregrind/m_gdbserver/riscv64-fpu.xml new file mode 100644 index 0000000000..ff42b4a21f --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-fpu.xml @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!-- Register numbers are hard-coded in order to maintain backward + compatibility with older versions of tools that didn't use xml + register descriptions. --> + +<!DOCTYPE feature SYSTEM "gdb-target.dtd"> +<feature name="org.gnu.gdb.riscv.fpu"> + + <union id="riscv_double"> + <field name="float" type="ieee_single"/> + <field name="double" type="ieee_double"/> + </union> + + <reg name="ft0" bitsize="64" type="riscv_double" regnum="33"/> + <reg name="ft1" bitsize="64" type="riscv_double"/> + <reg name="ft2" bitsize="64" type="riscv_double"/> + <reg name="ft3" bitsize="64" type="riscv_double"/> + <reg name="ft4" bitsize="64" type="riscv_double"/> + <reg name="ft5" bitsize="64" type="riscv_double"/> + <reg name="ft6" bitsize="64" type="riscv_double"/> + <reg name="ft7" bitsize="64" type="riscv_double"/> + <reg name="fs0" bitsize="64" type="riscv_double"/> + <reg name="fs1" bitsize="64" type="riscv_double"/> + <reg name="fa0" bitsize="64" type="riscv_double"/> + <reg name="fa1" bitsize="64" type="riscv_double"/> + <reg name="fa2" bitsize="64" type="riscv_double"/> + <reg name="fa3" bitsize="64" type="riscv_double"/> + <reg name="fa4" bitsize="64" type="riscv_double"/> + <reg name="fa5" bitsize="64" type="riscv_double"/> + <reg name="fa6" bitsize="64" type="riscv_double"/> + <reg name="fa7" bitsize="64" type="riscv_double"/> + <reg name="fs2" bitsize="64" type="riscv_double"/> + <reg name="fs3" bitsize="64" type="riscv_double"/> + <reg name="fs4" bitsize="64" type="riscv_double"/> + <reg name="fs5" bitsize="64" type="riscv_double"/> + <reg name="fs6" bitsize="64" type="riscv_double"/> + <reg name="fs7" bitsize="64" type="riscv_double"/> + <reg name="fs8" bitsize="64" type="riscv_double"/> + <reg name="fs9" bitsize="64" type="riscv_double"/> + <reg name="fs10" bitsize="64" type="riscv_double"/> + <reg name="fs11" bitsize="64" type="riscv_double"/> + <reg name="ft8" bitsize="64" type="riscv_double"/> + <reg name="ft9" bitsize="64" type="riscv_double"/> + <reg name="ft10" bitsize="64" type="riscv_double"/> + <reg name="ft11" bitsize="64" type="riscv_double"/> + + <reg name="fflags" bitsize="32" type="int" regnum="66"/> + <reg name="frm" bitsize="32" type="int" regnum="67"/> + <reg name="fcsr" bitsize="32" type="int" regnum="68"/> +</feature> diff --git a/coregrind/m_gdbserver/riscv64-linux-valgrind.xml b/coregrind/m_gdbserver/riscv64-linux-valgrind.xml new file mode 100644 index 0000000000..0227f2ee78 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-linux-valgrind.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<target> + <architecture>riscv</architecture> + <xi:include href="riscv64-cpu.xml"/> + <xi:include href="riscv64-fpu.xml"/> + <xi:include href="riscv64-cpu-valgrind-s1.xml"/> + <xi:include href="riscv64-fpu-valgrind-s1.xml"/> + <xi:include href="riscv64-cpu-valgrind-s2.xml"/> + <xi:include href="riscv64-fpu-valgrind-s2.xml"/> + + <feature name="org.gnu.gdb.riscv.linux"> + <reg name="restart" bitsize="64" group="system"/> + </feature> +</target> \ No newline at end of file diff --git a/coregrind/m_gdbserver/riscv64-linux.xml b/coregrind/m_gdbserver/riscv64-linux.xml new file mode 100644 index 0000000000..7c86312202 --- /dev/null +++ b/coregrind/m_gdbserver/riscv64-linux.xml @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<!-- Copyright (C) 2018-2022 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. --> + +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<target> + <architecture>riscv</architecture> + <xi:include href="riscv64-cpu.xml"/> + <xi:include href="riscv64-fpu.xml"/> + + <feature name="org.gnu.gdb.riscv.linux"> + <reg name="restart" bitsize="64" group="system"/> + </feature> +</target> \ No newline at end of file diff --git a/coregrind/m_gdbserver/valgrind-low-riscv64.c b/coregrind/m_gdbserver/valgrind-low-riscv64.c new file mode 100644 index 0000000000..75088fc1ec --- /dev/null +++ b/coregrind/m_gdbserver/valgrind-low-riscv64.c @@ -0,0 +1,287 @@ +/* Low level interface to valgrind, for the remote server for GDB integrated + in valgrind. + Copyright (C) 2022 + Free Software Foundation, Inc. + + This file is part of VALGRIND. + It has been inspired from a file from gdbserver in gdb 6.6. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#include "server.h" +#include "target.h" +#include "regdef.h" +#include "regcache.h" + +#include "pub_core_machine.h" +#include "pub_core_threadstate.h" +#include "pub_core_transtab.h" +#include "pub_core_gdbserver.h" +#include "pub_core_debuginfo.h" + +#include "valgrind_low.h" + +#include "libvex_guest_riscv64.h" + +/* from GDB gdb/features/riscv/64bit-{cpu,fpu}.c */ +static struct reg regs[] = { + { "zero", 0, 64 }, + { "ra", 64, 64 }, + { "sp", 128, 64 }, + { "gp", 192, 64 }, + { "tp", 256, 64 }, + { "t0", 320, 64 }, + { "t1", 384, 64 }, + { "t2", 448, 64 }, + { "fp", 512, 64 }, + { "s1", 576, 64 }, + { "a0", 640, 64 }, + { "a1", 704, 64 }, + { "a2", 768, 64 }, + { "a3", 832, 64 }, + { "a4", 896, 64 }, + { "a5", 960, 64 }, + { "a6", 1024, 64 }, + { "a7", 1088, 64 }, + { "s2", 1152, 64 }, + { "s3", 1216, 64 }, + { "s4", 1280, 64 }, + { "s5", 1344, 64 }, + { "s6", 1408, 64 }, + { "s7", 1472, 64 }, + { "s8", 1536, 64 }, + { "s9", 1600, 64 }, + { "s10", 1664, 64 }, + { "s11", 1728, 64 }, + { "t3", 1792, 64 }, + { "t4", 1856, 64 }, + { "t5", 1920, 64 }, + { "t6", 1984, 64 }, + { "pc", 2048, 64 }, + + { "ft0", 2112, 64 }, + { "ft1", 2176, 64 }, + { "ft2", 2240, 64 }, + { "ft3", 2304, 64 }, + { "ft4", 2368, 64 }, + { "ft5", 2432, 64 }, + { "ft6", 2496, 64 }, + { "ft7", 2560, 64 }, + { "fs0", 2624, 64 }, + { "fs1", 2688, 64 }, + { "fa0", 2752, 64 }, + { "fa1", 2816, 64 }, + { "fa2", 2880, 64 }, + { "fa3", 2944, 64 }, + { "fa4", 3008, 64 }, + { "fa5", 3072, 64 }, + { "fa6", 3136, 64 }, + { "fa7", 3200, 64 }, + { "fs2", 3264, 64 }, + { "fs3", 3328, 64 }, + { "fs4", 3392, 64 }, + { "fs5", 3456, 64 }, + { "fs6", 3520, 64 }, + { "fs7", 3584, 64 }, + { "fs8", 3648, 64 }, + { "fs9", 3712, 64 }, + { "fs10", 3776, 64 }, + { "fs11", 3840, 64 }, + { "ft8", 3904, 64 }, + { "ft9", 3968, 64 }, + { "ft10", 4032, 64 }, + { "ft11", 4096, 64 }, + { "", 4160, 0 }, /* regnums have a hole here */ + { "fflags", 4160, 32 }, + { "frm", 4192, 32 }, + { "fcsr", 4224, 32 }, +}; + +/* from GDB gdbserver/linux-riscv-low.cc */ +static const char *expedite_regs[] = { "sp", "pc", 0 }; + +#define num_regs (sizeof (regs) / sizeof (regs[0])) + +static +CORE_ADDR get_pc (void) +{ + unsigned long pc; + + collect_register_by_name ("pc", &pc); + + dlog(1, "stop pc is %p\n", (void *) pc); + return pc; +} + +static +void set_pc (CORE_ADDR newpc) +{ + supply_register_by_name ("pc", &newpc); +} + +/* store registers in the guest state (gdbserver_to_valgrind) + or fetch register from the guest state (valgrind_to_gdbserver). */ +static +void transfer_register (ThreadId tid, int abs_regno, void * buf, + transfer_direction dir, int size, Bool *mod) +{ + ThreadState* tst = VG_(get_ThreadState)(tid); + int set = abs_regno / num_regs; + int regno = abs_regno % num_regs; + *mod = False; + UInt v, *p; + + VexGuestRISCV64State* riscv = (VexGuestRISCV64State*) get_arch (set, tst); + + switch (regno) { + // numbers here have to match the order of regs above + // Attention: gdb order does not match valgrind order. + case 0: VG_(transfer) (&riscv->guest_x0, buf, dir, size, mod); break; + case 1: VG_(transfer) (&riscv->guest_x1, buf, dir, size, mod); break; + case 2: VG_(transfer) (&riscv->guest_x2, buf, dir, size, mod); break; + case 3: VG_(transfer) (&riscv->guest_x3, buf, dir, size, mod); break; + case 4: VG_(transfer) (&riscv->guest_x4, buf, dir, size, mod); break; + case 5: VG_(transfer) (&riscv->guest_x5, buf, dir, size, mod); break; + case 6: VG_(transfer) (&riscv->guest_x6, buf, dir, size, mod); break; + case 7: VG_(transfer) (&riscv->guest_x7, buf, dir, size, mod); break; + case 8: VG_(transfer) (&riscv->guest_x8, buf, dir, size, mod); break; + case 9: VG_(transfer) (&riscv->guest_x9, buf, dir, size, mod); break; + case 10: VG_(transfer) (&riscv->guest_x10, buf, dir, size, mod); break; + case 11: VG_(transfer) (&riscv->guest_x11, buf, dir, size, mod); break; + case 12: VG_(transfer) (&riscv->guest_x12, buf, dir, size, mod); break; + case 13: VG_(transfer) (&riscv->guest_x13, buf, dir, size, mod); break; + case 14: VG_(transfer) (&riscv->guest_x14, buf, dir, size, mod); break; + case 15: VG_(transfer) (&riscv->guest_x15, buf, dir, size, mod); break; + case 16: VG_(transfer) (&riscv->guest_x16, buf, dir, size, mod); break; + case 17: VG_(transfer) (&riscv->guest_x17, buf, dir, size, mod); break; + case 18: VG_(transfer) (&riscv->guest_x18, buf, dir, size, mod); break; + case 19: VG_(transfer) (&riscv->guest_x19, buf, dir, size, mod); break; + case 20: VG_(transfer) (&riscv->guest_x20, buf, dir, size, mod); break; + case 21: VG_(transfer) (&riscv->guest_x21, buf, dir, size, mod); break; + case 22: VG_(transfer) (&riscv->guest_x22, buf, dir, size, mod); break; + case 23: VG_(transfer) (&riscv->guest_x23, buf, dir, size, mod); break; + case 24: VG_(transfer) (&riscv->guest_x24, buf, dir, size, mod); break; + case 25: VG_(transfer) (&riscv->guest_x25, buf, dir, size, mod); break; + case 26: VG_(transfer) (&riscv->guest_x26, buf, dir, size, mod); break; + case 27: VG_(transfer) (&riscv->guest_x27, buf, dir, size, mod); break; + case 28: VG_(transfer) (&riscv->guest_x28, buf, dir, size, mod); break; + case 29: VG_(transfer) (&riscv->guest_x29, buf, dir, size, mod); break; + case 30: VG_(transfer) (&riscv->guest_x30, buf, dir, size, mod); break; + case 31: VG_(transfer) (&riscv->guest_x31, buf, dir, size, mod); break; + case 32: VG_(transfer) (&riscv->guest_pc, buf, dir, size, mod); break; + + case 33: VG_(transfer) (&riscv->guest_f0, buf, dir, size, mod); break; + case 34: VG_(transfer) (&riscv->guest_f1, buf, dir, size, mod); break; + case 35: VG_(transfer) (&riscv->guest_f2, buf, dir, size, mod); break; + case 36: VG_(transfer) (&riscv->guest_f3, buf, dir, size, mod); break; + case 37: VG_(transfer) (&riscv->guest_f4, buf, dir, size, mod); break; + case 38: VG_(transfer) (&riscv->guest_f5, buf, dir, size, mod); break; + case 39: VG_(transfer) (&riscv->guest_f6, buf, dir, size, mod); break; + case 40: VG_(transfer) (&riscv->guest_f7, buf, dir, size, mod); break; + case 41: VG_(transfer) (&riscv->guest_f8, buf, dir, size, mod); break; + case 42: VG_(transfer) (&riscv->guest_f9, buf, dir, size, mod); break; + case 43: VG_(transfer) (&riscv->guest_f10, buf, dir, size, mod); break; + case 44: VG_(transfer) (&riscv->guest_f11, buf, dir, size, mod); break; + case 45: VG_(transfer) (&riscv->guest_f12, buf, dir, size, mod); break; + case 46: VG_(transfer) (&riscv->guest_f13, buf, dir, size, mod); break; + case 47: VG_(transfer) (&riscv->guest_f14, buf, dir, size, mod); break; + case 48: VG_(transfer) (&riscv->guest_f15, buf, dir, size, mod); break; + case 49: VG_(transfer) (&riscv->guest_f16, buf, dir, size, mod); break; + case 50: VG_(transfer) (&riscv->guest_f17, buf, dir, size, mod); break; + case 51: VG_(transfer) (&riscv->guest_f18, buf, dir, size, mod); break; + case 52: VG_(transfer) (&riscv->guest_f19, buf, dir, size, mod); break; + case 53: VG_(transfer) (&riscv->guest_f20, buf, dir, size, mod); break; + case 54: VG_(transfer) (&riscv->guest_f21, buf, dir, size, mod); break; + case 55: VG_(transfer) (&riscv->guest_f22, buf, dir, size, mod); break; + case 56: VG_(transfer) (&riscv->guest_f23, buf, dir, size, mod); break; + case 57: VG_(transfer) (&riscv->guest_f24, buf, dir, size, mod); break; + case 58: VG_(transfer) (&riscv->guest_f25, buf, dir, size, mod); break; + case 59: VG_(transfer) (&riscv->guest_f26, buf, dir, size, mod); break; + case 60: VG_(transfer) (&riscv->guest_f27, buf, dir, size, mod); break; + case 61: VG_(transfer) (&riscv->guest_f28, buf, dir, size, mod); break; + case 62: VG_(transfer) (&riscv->guest_f29, buf, dir, size, mod); break; + case 63: VG_(transfer) (&riscv->guest_f30, buf, dir, size, mod); break; + case 64: VG_(transfer) (&riscv->guest_f31, buf, dir, size, mod); break; + + case 65: break; + + case 66: /* fflags = fcsr & 0x1F */ + p = &riscv->guest_fcsr; + if (dir == valgrind_to_gdbserver) + v = *p & 0x1F; + VG_(transfer) (&v, buf, dir, size, mod); + if (dir == gdbserver_to_valgrind) + *p = (*p & ~0x1F) | v; + break; + + case 67: /* frm = (fcsr & 0xE0) >> 5 */ + p = &riscv->guest_fcsr; + if (dir == valgrind_to_gdbserver) + v = (*p & 0xE0) >> 5; + VG_(transfer) (&v, buf, dir, size, mod); + if (dir == gdbserver_to_valgrind) + *p = (*p & ~0xE0) | (v << 5); + break; + + case 68: VG_(transfer) (&riscv->guest_fcsr, buf, dir, size, mod); break; + default: vg_assert(0); + } +} + +static +const char* target_xml (Bool shadow_mode) +{ + if (shadow_mode) { + return "riscv64-linux-valgrind.xml"; + } else { + return "riscv64-linux.xml"; + } +} + +static CORE_ADDR** target_get_dtv (ThreadState *tst) +{ + VexGuestRISCV64State* riscv = (VexGuestRISCV64State*)&tst->arch.vex; + + /* RISC-V uses Variant I as described by the ELF TLS specification, + with tp containing the address one past the end of the TCB. + + from GLIBC sysdeps/riscv/nptl/tls.h, tp is just after tcbhead_t + typedef struct { + dtv_t *dtv; + void *private; + } tcbhead_t; + */ + return (CORE_ADDR**)(void *)(riscv->guest_x4 - 2 * sizeof(void *)); +} + +static struct valgrind_target_ops low_target = { + num_regs, + 2, //SP + regs, + transfer_register, + get_pc, + set_pc, + "riscv64", + target_xml, + target_get_dtv +}; + +void riscv64_init_architecture (struct valgrind_target_ops *target) +{ + *target = low_target; + set_register_cache (regs, num_regs); + gdbserver_expedite_regs = expedite_regs; +} diff --git a/coregrind/m_sigframe/sigframe-riscv64-linux.c b/coregrind/m_sigframe/sigframe-riscv64-linux.c new file mode 100644 index 0000000000..8ef05407eb --- /dev/null +++ b/coregrind/m_sigframe/sigframe-riscv64-linux.c @@ -0,0 +1,422 @@ + +/*--------------------------------------------------------------------*/ +/*--- Create/destroy signal delivery frames. ---*/ +/*--- sigframe-riscv64-linux.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_riscv64_linux) + +#include "libvex_guest_offsets.h" +#include "priv_sigframe.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_basics.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcprint.h" +#include "pub_core_machine.h" +#include "pub_core_options.h" +#include "pub_core_sigframe.h" +#include "pub_core_signals.h" +#include "pub_core_threadstate.h" +#include "pub_core_tooliface.h" +#include "pub_core_trampoline.h" +#include "pub_core_vki.h" + +/*------------------------------------------------------------*/ +/*--- Signal frame layout ---*/ +/*------------------------------------------------------------*/ + +/* Valgrind-specific parts of the signal frame. */ +struct vg_sigframe { + /* Sanity check word. */ + UInt magicPI; + + /* Safely-saved version of sigNo. */ + Int sigNo_private; + + /* Sanity check word. */ + UInt magicE; +}; + +/* Complete signal frame. */ +struct rt_sigframe { + struct vki_siginfo info; + struct vki_ucontext uc; + struct vg_sigframe vg; +}; + +/*------------------------------------------------------------*/ +/*--- Creating a signal frame ---*/ +/*------------------------------------------------------------*/ + +static void synth_ucontext(ThreadState* tst, + const vki_siginfo_t* si, + const vki_sigset_t* set, + struct vki_ucontext* uc) +{ + VG_(memset)(uc, 0, sizeof(*uc)); + + /* Prepare common data. */ + uc->uc_flags = 0; + VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, (Addr)&uc->uc_flags, + sizeof(uc->uc_flags)); + uc->uc_link = 0; + VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, (Addr)&uc->uc_link, + sizeof(uc->uc_link)); + uc->uc_sigmask = *set; + VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, (Addr)&uc->uc_sigmask, + sizeof(uc->uc_sigmask)); + uc->uc_stack = tst->altstack; + VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, (Addr)&uc->uc_stack, + sizeof(uc->uc_stack)); + + struct vki_sigcontext* sc = &uc->uc_mcontext; + + /* Save integer registers. */ +#define IREG_TO_CTX(ureg, vreg) \ + sc->sc_regs.ureg = tst->arch.vex.guest_##vreg; \ + VG_TRACK(copy_reg_to_mem, Vg_CoreSignal, tst->tid, OFFSET_riscv64_##vreg, \ + (Addr)&sc->sc_regs.ureg, sizeof(UWord)); + IREG_TO_CTX(pc, pc); + IREG_TO_CTX(ra, x1); + IREG_TO_CTX(sp, x2); + IREG_TO_CTX(gp, x3); + IREG_TO_CTX(tp, x4); + IREG_TO_CTX(t0, x5); + IREG_TO_CTX(t1, x6); + IREG_TO_CTX(t2, x7); + IREG_TO_CTX(s0, x8); + IREG_TO_CTX(s1, x9); + IREG_TO_CTX(a0, x10); + IREG_TO_CTX(a1, x11); + IREG_TO_CTX(a2, x12); + IREG_TO_CTX(a3, x13); + IREG_TO_CTX(a4, x14); + IREG_TO_CTX(a5, x15); + IREG_TO_CTX(a6, x16); + IREG_TO_CTX(a7, x17); + IREG_TO_CTX(s2, x18); + IREG_TO_CTX(s3, x19); + IREG_TO_CTX(s4, x20); + IREG_TO_CTX(s5, x21); + IREG_TO_CTX(s6, x22); + IREG_TO_CTX(s7, x23); + IREG_TO_CTX(s8, x24); + IREG_TO_CTX(s9, x25); + IREG_TO_CTX(s10, x26); + IREG_TO_CTX(s11, x27); + IREG_TO_CTX(t3, x28); + IREG_TO_CTX(t4, x29); + IREG_TO_CTX(t5, x30); + IREG_TO_CTX(t6, x31); +#undef IREG_TO_CTX + + /* Save floating point registers. */ +#define FREG_TO_CTX(ureg, vreg, type) \ + sc->sc_fpregs.d.ureg = tst->arch.vex.guest_##vreg; \ + VG_TRACK(copy_reg_to_mem, Vg_CoreSignal, tst->tid, OFFSET_riscv64_##vreg, \ + (Addr)&sc->sc_fpregs.d.ureg, sizeof(type)); + FREG_TO_CTX(f[0], f0, UWord); + FREG_TO_CTX(f[1], f1, UWord); + FREG_TO_CTX(f[2], f2, UWord); + FREG_TO_CTX(f[3], f3, UWord); + FREG_TO_CTX(f[4], f4, UWord); + FREG_TO_CTX(f[5], f5, UWord); + FREG_TO_CTX(f[6], f6, UWord); + FREG_TO_CTX(f[7], f7, UWord); + FREG_TO_CTX(f[8], f8, UWord); + FREG_TO_CTX(f[9], f9, UWord); + FREG_TO_CTX(f[10], f10, UWord); + FREG_TO_CTX(f[11], f11, UWord); + FREG_TO_CTX(f[12], f12, UWord); + FREG_TO_CTX(f[13], f13, UWord); + FREG_TO_CTX(f[14], f14, UWord); + FREG_TO_CTX(f[15], f15, UWord); + FREG_TO_CTX(f[16], f16, UWord); + FREG_TO_CTX(f[17], f17, UWord); + FREG_TO_CTX(f[18], f18, UWord); + FREG_TO_CTX(f[19], f19, UWord); + FREG_TO_CTX(f[20], f20, UWord); + FREG_TO_CTX(f[21], f21, UWord); + FREG_TO_CTX(f[22], f22, UWord); + FREG_TO_CTX(f[23], f23, UWord); + FREG_TO_CTX(f[24], f24, UWord); + FREG_TO_CTX(f[25], f25, UWord); + FREG_TO_CTX(f[26], f26, UWord); + FREG_TO_CTX(f[27], f27, UWord); + FREG_TO_CTX(f[28], f28, UWord); + FREG_TO_CTX(f[29], f29, UWord); + FREG_TO_CTX(f[30], f30, UWord); + FREG_TO_CTX(f[31], f31, UWord); + FREG_TO_CTX(fcsr, fcsr, UInt); +#undef FREG_TO_CTX +} + +/* Build the Valgrind-specific part of a signal frame. */ +static void build_vg_sigframe(struct vg_sigframe* frame, Int sigNo) +{ + frame->magicPI = 0x31415927; + frame->sigNo_private = sigNo; + frame->magicE = 0x27182818; +} + +static Addr build_rt_sigframe(ThreadState* tst, + Addr sp_top_of_frame, + const vki_siginfo_t* siginfo, + UInt flags, + const vki_sigset_t* mask) +{ + SizeT size = sizeof(struct rt_sigframe); + Addr sp = VG_ROUNDDN(sp_top_of_frame - size, 16); + + if (!ML_(sf_maybe_extend_stack)(tst, sp, size, flags)) + return sp_top_of_frame; + + /* Tell the tools that the sigframe is to be written. */ + VG_TRACK(pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", sp, + sizeof(struct rt_sigframe)); + + struct rt_sigframe* frame = (struct rt_sigframe*)sp; + + /* Fill in the siginfo. */ + frame->info = *siginfo; + + /* SIGILL defines addr to be the faulting address. */ + Int sigNo = siginfo->si_signo; + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + frame->info._sifields._sigfault._addr = (void*)VG_(get_IP)(tst->tid); + + VG_TRACK(post_mem_write, Vg_CoreSignal, tst->tid, (Addr)&frame->info, + sizeof(frame->info)); + + /* Fill in the ucontext. */ + synth_ucontext(tst, siginfo, mask, &frame->uc); + + /* Fill in the Valgrind-specific part. */ + build_vg_sigframe(&frame->vg, sigNo); + + return sp; +} + +void VG_(sigframe_create)(ThreadId tid, + Bool on_altstack, + Addr rsp_top_of_frame, + const vki_siginfo_t* siginfo, + const struct vki_ucontext* siguc, + void* handler, + UInt flags, + const vki_sigset_t* mask, + void* restorer) +{ + /* The restorer functionality (SA_RESTORER) is not used on riscv64-linux. */ + vg_assert(restorer == NULL); + + ThreadState* tst = VG_(get_ThreadState)(tid); + + /* Build the signal frame on the stack. */ + Addr sp = build_rt_sigframe(tst, rsp_top_of_frame, siginfo, flags, mask); + struct rt_sigframe* frame = (struct rt_sigframe*)sp; + + /* Configure guest registers for the signal delivery. */ + VG_(set_SP)(tid, sp); + VG_TRACK(post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UWord)); + + tst->arch.vex.guest_x10 = siginfo->si_signo; + VG_TRACK(post_reg_write, Vg_CoreSignal, tst->tid, OFFSET_riscv64_x10, + sizeof(UWord)); + tst->arch.vex.guest_x11 = (Addr)&frame->info; + VG_TRACK(post_reg_write, Vg_CoreSignal, tst->tid, OFFSET_riscv64_x11, + sizeof(UWord)); + tst->arch.vex.guest_x12 = (Addr)&frame->uc; + VG_TRACK(post_reg_write, Vg_CoreSignal, tst->tid, OFFSET_riscv64_x12, + sizeof(UWord)); + + tst->arch.vex.guest_x1 = (Addr)&VG_(riscv64_linux_SUBST_FOR_rt_sigreturn); + VG_TRACK(post_reg_write, Vg_CoreSignal, tst->tid, OFFSET_riscv64_x1, + sizeof(UWord)); + + /* Set up the program counter. Note that it is not necessary to inform the + tools about this write because pc is always defined. */ + VG_(set_IP)(tid, (Addr)handler); + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, + "sigframe_create (thread %u): next pc=%#lx, next sp=%#lx\n", + tid, (Addr)handler, sp); +} + +/*------------------------------------------------------------*/ +/*--- Destroying a signal frame ---*/ +/*------------------------------------------------------------*/ + +/* Restore the Valgrind-specific part of a signal frame. The returned value + indicates whether the frame is valid. If not then nothing is restored and the + client is set to take a segfault. */ +static Bool +restore_vg_sigframe(ThreadState* tst, struct vg_sigframe* frame, Int* sigNo) +{ + if (frame->magicPI != 0x31415927 || frame->magicE != 0x27182818) { + VG_(message)( + Vg_UserMsg, + "Thread %u return signal frame corrupted. Killing process.\n", + tst->tid); + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault)(tst->tid); + *sigNo = VKI_SIGSEGV; + return False; + } + *sigNo = frame->sigNo_private; + return True; +} + +static void restore_ucontext(ThreadState* tst, struct vki_ucontext* uc) +{ + /* Restore common data. */ + VG_TRACK(pre_mem_read, Vg_CoreSignal, tst->tid, "signal frame mask", + (Addr)&uc->uc_sigmask, sizeof(uc->uc_sigmask)); + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = tst->sig_mask; + + struct vki_sigcontext* sc = &uc->uc_mcontext; + + /* Restore integer registers. */ +#define IREG_FROM_CTX(ureg, vreg) \ + tst->arch.vex.guest_##vreg = sc->sc_regs.ureg; \ + VG_TRACK(copy_mem_to_reg, Vg_CoreSignal, tst->tid, (Addr)&sc->sc_regs.ureg, \ + OFFSET_riscv64_##vreg, sizeof(UWord)); + IREG_FROM_CTX(pc, pc); + IREG_FROM_CTX(ra, x1); + IREG_FROM_CTX(sp, x2); + IREG_FROM_CTX(gp, x3); + IREG_FROM_CTX(tp, x4); + IREG_FROM_CTX(t0, x5); + IREG_FROM_CTX(t1, x6); + IREG_FROM_CTX(t2, x7); + IREG_FROM_CTX(s0, x8); + IREG_FROM_CTX(s1, x9); + IREG_FROM_CTX(a0, x10); + IREG_FROM_CTX(a1, x11); + IREG_FROM_CTX(a2, x12); + IREG_FROM_CTX(a3, x13); + IREG_FROM_CTX(a4, x14); + IREG_FROM_CTX(a5, x15); + IREG_FROM_CTX(a6, x16); + IREG_FROM_CTX(a7, x17); + IREG_FROM_CTX(s2, x18); + IREG_FROM_CTX(s3, x19); + IREG_FROM_CTX(s4, x20); + IREG_FROM_CTX(s5, x21); + IREG_FROM_CTX(s6, x22); + IREG_FROM_CTX(s7, x23); + IREG_FROM_CTX(s8, x24); + IREG_FROM_CTX(s9, x25); + IREG_FROM_CTX(s10, x26); + IREG_FROM_CTX(s11, x27); + IREG_FROM_CTX(t3, x28); + IREG_FROM_CTX(t4, x29); + IREG_FROM_CTX(t5, x30); + IREG_FROM_CTX(t6, x31); +#undef IREG_FROM_CTX + + /* Restore floating point registers. */ +#define FREG_FROM_CTX(ureg, vreg, type) \ + tst->arch.vex.guest_##vreg = sc->sc_fpregs.d.ureg; \ + VG_TRACK(copy_mem_to_reg, Vg_CoreSignal, tst->tid, \ + (Addr)&sc->sc_fpregs.d.ureg, OFFSET_riscv64_##vreg, sizeof(type)); + FREG_FROM_CTX(f[0], f0, UWord); + FREG_FROM_CTX(f[1], f1, UWord); + FREG_FROM_CTX(f[2], f2, UWord); + FREG_FROM_CTX(f[3], f3, UWord); + FREG_FROM_CTX(f[4], f4, UWord); + FREG_FROM_CTX(f[5], f5, UWord); + FREG_FROM_CTX(f[6], f6, UWord); + FREG_FROM_CTX(f[7], f7, UWord); + FREG_FROM_CTX(f[8], f8, UWord); + FREG_FROM_CTX(f[9], f9, UWord); + FREG_FROM_CTX(f[10], f10, UWord); + FREG_FROM_CTX(f[11], f11, UWord); + FREG_FROM_CTX(f[12], f12, UWord); + FREG_FROM_CTX(f[13], f13, UWord); + FREG_FROM_CTX(f[14], f14, UWord); + FREG_FROM_CTX(f[15], f15, UWord); + FREG_FROM_CTX(f[16], f16, UWord); + FREG_FROM_CTX(f[17], f17, UWord); + FREG_FROM_CTX(f[18], f18, UWord); + FREG_FROM_CTX(f[19], f19, UWord); + FREG_FROM_CTX(f[20], f20, UWord); + FREG_FROM_CTX(f[21], f21, UWord); + FREG_FROM_CTX(f[22], f22, UWord); + FREG_FROM_CTX(f[23], f23, UWord); + FREG_FROM_CTX(f[24], f24, UWord); + FREG_FROM_CTX(f[25], f25, UWord); + FREG_FROM_CTX(f[26], f26, UWord); + FREG_FROM_CTX(f[27], f27, UWord); + FREG_FROM_CTX(f[28], f28, UWord); + FREG_FROM_CTX(f[29], f29, UWord); + FREG_FROM_CTX(f[30], f30, UWord); + FREG_FROM_CTX(f[31], f31, UWord); + FREG_FROM_CTX(fcsr, fcsr, UInt); +#undef FREG_FROM_CTX +} + +static void +restore_rt_sigframe(ThreadState* tst, struct rt_sigframe* frame, Int* sigNo) +{ + if (restore_vg_sigframe(tst, &frame->vg, sigNo)) + restore_ucontext(tst, &frame->uc); +} + +void VG_(sigframe_destroy)(ThreadId tid, Bool isRT) +{ + /* Non-rt sigreturn does not exist on riscv64-linux. */ + vg_assert(isRT); + + ThreadState* tst = VG_(get_ThreadState)(tid); + + /* Correctly reestablish the frame base address. */ + Addr sp = VG_(get_SP)(tid); + + /* Restore a state from the signal frame. */ + Int sigNo; + restore_rt_sigframe(tst, (struct rt_sigframe*)sp, &sigNo); + + VG_TRACK(die_mem_stack_signal, sp - VG_STACK_REDZONE_SZB, + sizeof(struct rt_sigframe) + VG_STACK_REDZONE_SZB); + + /* Returning from a signal handler. */ + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "sigframe_return (thread %u): pc=%#lx\n", tid, + VG_(get_IP)(tid)); + + /* Tell the tools. */ + VG_TRACK(post_deliver_signal, tid, sigNo); +} + +#endif // defined(VGP_riscv64_linux) + +/*--------------------------------------------------------------------*/ +/*--- end sigframe-riscv64-linux.c ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syscall-riscv64-linux.S b/coregrind/m_syswrap/syscall-riscv64-linux.S new file mode 100644 index 0000000000..cf976cee18 --- /dev/null +++ b/coregrind/m_syswrap/syscall-riscv64-linux.S @@ -0,0 +1,198 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-riscv64-linux.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2020-2023 Petr Pavlu + pet...@da... + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_riscv64_linux) + +#include "pub_core_vkiscnums_asm.h" +#include "libvex_guest_offsets.h" + + +/*----------------------------------------------------------------*/ +/* + Perform a syscall for the client. This will run a syscall + with the client's specific per-thread signal mask. + + The structure of this function is such that, if the syscall is + interrupted by a signal, we can determine exactly what + execution state we were in with respect to the execution of + the syscall by examining the value of pc in the signal + handler. This means that we can always do the appropriate + thing to precisely emulate the kernel's signal/syscall + interactions. + + The syscall number is taken from the argument, even though it + should also be in guest_state->guest_x17. The syscall result + is written back to guest_state->guest_x10 on completion. + + Returns 0 if the syscall was successfully called (even if the + syscall itself failed), or a nonzero error code in the lowest + 8 bits if one of the sigprocmasks failed (there's no way to + determine which one failed). And there's no obvious way to + recover from that either, but nevertheless we want to know. + + VG_(fixup_guest_state_after_syscall_interrupted) does the + thread state fixup in the case where we were interrupted by a + signal. + + Prototype: + + UWord ML_(do_syscall_for_client_WRK)( + Int syscallno, // a0 + void* guest_state, // a1 + const vki_sigset_t *sysmask, // a2 + const vki_sigset_t *postmask, // a3 + Int nsigwords) // a4 +*/ +/* from vki-riscv64-linux.h */ +#define VKI_SIG_SETMASK 2 + +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): + + /* Stash callee-saves and our args on the stack */ + addi sp, sp, -144 + sd ra, 136(sp) + sd s0, 128(sp) + sd s1, 120(sp) + sd s2, 112(sp) + sd s3, 104(sp) + sd s4, 96(sp) + sd s5, 88(sp) + sd s6, 80(sp) + sd s7, 72(sp) + sd s8, 64(sp) + sd s9, 56(sp) + sd s10, 48(sp) + sd s11, 40(s... [truncated message content] |