From bd13e8e206e6c86581cf9afa904ef1060351a4b0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 10 Apr 2020 02:46:33 -0700 Subject: [PATCH] util: Add a "semi" call type unit test to the m5 utility. This is largely similar to the "inst" call type test since it's also another form of illegal instruction, but there's more checking to do since the way arguments are passed is more complex. Change-Id: Ie61bb4da8befab579c3044fd2ddee753926de174 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27749 Reviewed-by: Jason Lowe-Power Maintainer: Jason Lowe-Power Tested-by: kokoro --- util/m5/src/abi/aarch64/SConsopts | 2 +- util/m5/src/abi/aarch64/verify_semi.cc | 54 +++++++++++ util/m5/src/call_type/semi.test.cc | 126 +++++++++++++++++++++++++ util/m5/src/call_type/verify_semi.hh | 37 ++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 util/m5/src/abi/aarch64/verify_semi.cc create mode 100644 util/m5/src/call_type/verify_semi.hh diff --git a/util/m5/src/abi/aarch64/SConsopts b/util/m5/src/abi/aarch64/SConsopts index 47ada0209..010b22ec7 100644 --- a/util/m5/src/abi/aarch64/SConsopts +++ b/util/m5/src/abi/aarch64/SConsopts @@ -30,4 +30,4 @@ get_abi_opt('CROSS_COMPILE', 'aarch64-linux-gnu-') env['CALL_TYPE']['inst'].impl('m5op.S', 'verify_inst.cc', default=True) env['CALL_TYPE']['addr'].impl('m5op_addr.S') -env['CALL_TYPE']['semi'].impl('m5op_semi.S') +env['CALL_TYPE']['semi'].impl('m5op_semi.S', 'verify_semi.cc') diff --git a/util/m5/src/abi/aarch64/verify_semi.cc b/util/m5/src/abi/aarch64/verify_semi.cc new file mode 100644 index 000000000..c3cc77ed4 --- /dev/null +++ b/util/m5/src/abi/aarch64/verify_semi.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2020 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "call_type/verify_semi.hh" + +extern uint64_t m5_semi_argument_block[]; + +void +abi_verify_semi(const siginfo_t &info, int func, + const std::vector &args) +{ + // Extract the instruction that triggered the signal. + uint32_t inst = *(uint32_t *)info.si_addr; + + // Get the imm16 field from it. + uint32_t imm16 = (inst >> 5) & 0xffff; + + // Verify that it used the gem5 immediate value. + EXPECT_EQ(imm16, 0x5d57); + + // Check that the right function was called. + EXPECT_EQ(func, (m5_semi_argument_block[0] >> 8) & 0xff); + + // Check that the arguments were correct. + uint64_t *arg = &m5_semi_argument_block[1]; + for (uint64_t expected: args) + EXPECT_EQ(*arg++, expected); +} diff --git a/util/m5/src/call_type/semi.test.cc b/util/m5/src/call_type/semi.test.cc index 10f3d0e53..6c17a06eb 100644 --- a/util/m5/src/call_type/semi.test.cc +++ b/util/m5/src/call_type/semi.test.cc @@ -27,8 +27,134 @@ #include +#include +#include +#include +#include +#include + +#include "args.hh" #include "call_type.hh" +#include "call_type/verify_semi.hh" +#include "dispatch_table.hh" + +class DefaultCallType : public CallType +{ + private: + DispatchTable dt; + + public: + DefaultCallType() : CallType("default") {} + + bool init_called = false; + void init() override { init_called = true; } + + bool isDefault() const override { return true; } + void printDesc(std::ostream &os) const override {} + const DispatchTable &getDispatch() const override { return dt; } +}; + +DefaultCallType default_call_type; + +TEST(SemiCallType, Detect) +{ + CallType *ct; + + // Semi should not be selected if there are no arguments. + Args empty({}); + default_call_type.init_called = false; + ct = CallType::detect(empty); + EXPECT_EQ(ct, &default_call_type); + EXPECT_TRUE(default_call_type.init_called); + + // Inst should not be selected if --semi isn't the first argument. + Args one_arg({"one"}); + default_call_type.init_called = false; + ct = CallType::detect(one_arg); + EXPECT_EQ(ct, &default_call_type); + EXPECT_TRUE(default_call_type.init_called); + + // Semi should be selected if --semi is the first argument. + Args selected({"--semi"}); + default_call_type.init_called = false; + ct = CallType::detect(selected); + EXPECT_NE(ct, &default_call_type); + EXPECT_NE(ct, nullptr); + EXPECT_FALSE(default_call_type.init_called); + + Args extra({"--semi", "foo"}); + default_call_type.init_called = false; + ct = CallType::detect(extra); + EXPECT_NE(ct, &default_call_type); + EXPECT_NE(ct, nullptr); + EXPECT_FALSE(default_call_type.init_called); + + // Semi should not be selected if --semi isn't first. + Args not_first({"foo", "--semi"}); + default_call_type.init_called = false; + ct = CallType::detect(not_first); + EXPECT_EQ(ct, &default_call_type); + EXPECT_TRUE(default_call_type.init_called); +} + +sigjmp_buf intercept_env; +siginfo_t intercept_siginfo; + +void +sigill_handler(int sig, siginfo_t *info, void *ucontext) +{ + std::memcpy(&intercept_siginfo, info, sizeof(intercept_siginfo)); + siglongjmp(intercept_env, 1); +} TEST(SemiCallType, Sum) { + // Get the semi call type, which is in an anonymous namespace. + Args args({"--semi"}); + CallType *semi_call_type = CallType::detect(args); + EXPECT_NE(semi_call_type, nullptr); + + // Get the dispatch table associated with it. + const auto &dt = semi_call_type->getDispatch(); + + // Determine if we're running within gem5 by checking whether a flag is + // set in the environment. + bool in_gem5 = (std::getenv("RUNNING_IN_GEM5") != nullptr); + if (in_gem5) + std::cout << "In gem5, m5 ops should work." << std::endl; + else + std::cout << "Not in gem5, m5 ops won't work." << std::endl; + + // If it is, then we should be able to run the "sum" command. + if (in_gem5) { + EXPECT_EQ((*dt.m5_sum)(2, 2, 0, 0, 0, 0), 4); + return; + } + + // If not, then we'll need to try to catch the fall out from trying to run + // an m5 op and verify that what we were trying looks correct. + + struct sigaction sigill_action; + std::memset(&sigill_action, 0, sizeof(sigill_action)); + sigill_action.sa_sigaction = &sigill_handler; + sigill_action.sa_flags = SA_SIGINFO | SA_RESETHAND; + + struct sigaction old_sigill_action; + + sigaction(SIGILL, &sigill_action, &old_sigill_action); + + if (!sigsetjmp(intercept_env, 1)) { + (*dt.m5_sum)(2, 2, 0, 0, 0, 0); + sigaction(SIGILL, &old_sigill_action, nullptr); + ADD_FAILURE() << "Didn't die when attempting to run \"sum\"."; + return; + } + + // Back from siglongjump. + auto &info = intercept_siginfo; + + EXPECT_EQ(info.si_signo, SIGILL); + EXPECT_TRUE(info.si_code == ILL_ILLOPC || info.si_code == ILL_ILLOPN); + + abi_verify_semi(info, M5OP_SUM, {2, 2, 0, 0, 0, 0}); } diff --git a/util/m5/src/call_type/verify_semi.hh b/util/m5/src/call_type/verify_semi.hh new file mode 100644 index 000000000..02aa5cc8d --- /dev/null +++ b/util/m5/src/call_type/verify_semi.hh @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#ifndef __VERIFY_SEMI_HH__ +#define __VERIFY_SEMI_HH__ + +void abi_verify_semi(const siginfo_t &info, int func, + const std::vector &args); + +#endif // __VERIFY_SEMI_HH__ -- 2.30.2