| // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <gtest/gtest.h> | 
 |  | 
 | #include "tools/fidlcat/interception_tests/interception_workflow_test.h" | 
 |  | 
 | namespace fidlcat { | 
 |  | 
 | // zx_channel_create tests. | 
 |  | 
 | std::unique_ptr<SystemCallTest> ZxChannelCreate(int64_t result, std::string_view result_name, | 
 |                                                 uint32_t options, zx_handle_t* out0, | 
 |                                                 zx_handle_t* out1) { | 
 |   auto value = std::make_unique<SystemCallTest>("zx_channel_create", result, result_name); | 
 |   value->AddInput(options); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(out0)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(out1)); | 
 |   return value; | 
 | } | 
 |  | 
 | // Checks that we can decode a zx_channel_create syscall. | 
 | // Also checks that we create the right semantic for the channels. | 
 | #define CREATE_DISPLAY_TEST_CONTENT(errno, expected)                                         \ | 
 |   zx_handle_t out0 = 0x12345678;                                                             \ | 
 |   zx_handle_t out1 = 0x87654321;                                                             \ | 
 |   ProcessController controller(this, session(), loop());                                     \ | 
 |   PerformDisplayTest(&controller, "$plt(zx_channel_create)",                                 \ | 
 |                      ZxChannelCreate(errno, #errno, 0, &out0, &out1), expected);             \ | 
 |   SyscallDecoderDispatcher* dispatcher = controller.workflow().syscall_decoder_dispatcher(); \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info0 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kFirstPid, out0);                        \ | 
 |   ASSERT_NE(info0, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info0->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info0->fd(), 0);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info1 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kFirstPid, out1);                        \ | 
 |   ASSERT_NE(info1, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info1->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info1->fd(), 1);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info2 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kSecondPid, out0);                       \ | 
 |   ASSERT_NE(info2, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info2->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info2->fd(), 2);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info3 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kSecondPid, out1);                       \ | 
 |   ASSERT_NE(info3, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info3->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info3->fd(), 3);                                                                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kFirstPid, out0), out1);                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kFirstPid, out1), out0);                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kSecondPid, out0), out1);                \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kSecondPid, out1), out0); | 
 |  | 
 | #define CREATE_DISPLAY_TEST(name, errno, expected)                                            \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) { CREATE_DISPLAY_TEST_CONTENT(errno, expected); } \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) { CREATE_DISPLAY_TEST_CONTENT(errno, expected); } | 
 |  | 
 | CREATE_DISPLAY_TEST( | 
 |     ZxChannelCreate, ZX_OK, | 
 |     "\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_create(" | 
 |     "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |     "  -> \x1B[32mZX_OK\x1B[0m (out0: \x1B[32mhandle\x1B[0m = \x1B[31m12345678\x1B[0m, " | 
 |     "out1: \x1B[32mhandle\x1B[0m = \x1B[31m87654321\x1B[0m)\n"); | 
 |  | 
 | // Checks that we can decode a zx_channel_create syscall with interleaved responses. | 
 | // Also checks that we create the right semantic for the channels. | 
 | #define CREATE_INTERLEAVED_DISPLAY_TEST_CONTENT(errno, expected)                             \ | 
 |   zx_handle_t out0 = 0x12345678;                                                             \ | 
 |   zx_handle_t out1 = 0x87654321;                                                             \ | 
 |   ProcessController controller(this, session(), loop());                                     \ | 
 |   PerformInterleavedDisplayTest(&controller, "$plt(zx_channel_create)",                      \ | 
 |                                 ZxChannelCreate(errno, #errno, 0, &out0, &out1), expected);  \ | 
 |   SyscallDecoderDispatcher* dispatcher = controller.workflow().syscall_decoder_dispatcher(); \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info0 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kFirstPid, out0);                        \ | 
 |   ASSERT_NE(info0, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info0->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info0->fd(), 0);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info1 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kFirstPid, out1);                        \ | 
 |   ASSERT_NE(info1, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info1->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info1->fd(), 1);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info2 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kSecondPid, out0);                       \ | 
 |   ASSERT_NE(info2, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info2->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info2->fd(), 2);                                                                 \ | 
 |   const fidl_codec::semantic::InferredHandleInfo* info3 =                                    \ | 
 |       dispatcher->inference().GetInferredHandleInfo(kSecondPid, out1);                       \ | 
 |   ASSERT_NE(info3, nullptr);                                                                 \ | 
 |   ASSERT_EQ(info3->type(), "channel");                                                       \ | 
 |   ASSERT_EQ(info3->fd(), 3);                                                                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kFirstPid, out0), out1);                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kFirstPid, out1), out0);                 \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kSecondPid, out0), out1);                \ | 
 |   ASSERT_EQ(dispatcher->inference().GetLinkedHandle(kSecondPid, out1), out0); | 
 |  | 
 | #define CREATE_INTERLEAVED_DISPLAY_TEST(name, errno, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {                  \ | 
 |     CREATE_INTERLEAVED_DISPLAY_TEST_CONTENT(errno, expected);  \ | 
 |   }                                                            \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {                  \ | 
 |     CREATE_INTERLEAVED_DISPLAY_TEST_CONTENT(errno, expected);  \ | 
 |   } | 
 |  | 
 | CREATE_INTERLEAVED_DISPLAY_TEST( | 
 |     ZxChannelCreateInterleaved, ZX_OK, | 
 |     "\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_create(" | 
 |     "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |     "\n" | 
 |     "test_2718 \x1B[31m2718\x1B[0m:\x1B[31m8765\x1B[0m zx_channel_create(" | 
 |     "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |     "\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m   -> \x1B[32mZX_OK\x1B[0m (" | 
 |     "out0: \x1B[32mhandle\x1B[0m = \x1B[31m12345678\x1B[0m, " | 
 |     "out1: \x1B[32mhandle\x1B[0m = \x1B[31m87654321\x1B[0m)\n" | 
 |     "\n" | 
 |     "test_2718 \x1B[31m2718\x1B[0m:\x1B[31m8765\x1B[0m   -> \x1B[32mZX_OK\x1B[0m (" | 
 |     "out0: \x1B[32mhandle\x1B[0m = \x1B[31m12345678\x1B[0m, " | 
 |     "out1: \x1B[32mhandle\x1B[0m = \x1B[31m87654321\x1B[0m)\n"); | 
 |  | 
 | // zx_channel_write_tests. | 
 |  | 
 | std::unique_ptr<SystemCallTest> ZxChannelWrite(int64_t result, std::string_view result_name, | 
 |                                                zx_handle_t handle, uint32_t options, | 
 |                                                const uint8_t* bytes, uint32_t num_bytes, | 
 |                                                const zx_handle_t* handles, uint32_t num_handles) { | 
 |   auto value = std::make_unique<SystemCallTest>("zx_channel_write", result, result_name); | 
 |   value->AddInput(handle); | 
 |   value->AddInput(options); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(bytes)); | 
 |   value->AddInput(num_bytes); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(handles)); | 
 |   value->AddInput(num_handles); | 
 |   return value; | 
 | } | 
 |  | 
 | #define WRITE_CHECK_TEST_CONTENT(errno)                                                          \ | 
 |   data().set_check_bytes();                                                                      \ | 
 |   data().set_check_handles();                                                                    \ | 
 |   PerformCheckTest("$plt(zx_channel_write)",                                                     \ | 
 |                    ZxChannelWrite(errno, #errno, kHandle, 0, data().bytes(), data().num_bytes(), \ | 
 |                                   data().handles(), data().num_handles()),                       \ | 
 |                    nullptr) | 
 |  | 
 | #define WRITE_CHECK_TEST(name, errno)                                            \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) { WRITE_CHECK_TEST_CONTENT(errno); } \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) { WRITE_CHECK_TEST_CONTENT(errno); } | 
 |  | 
 | WRITE_CHECK_TEST(ZxChannelWriteCheck, ZX_OK); | 
 |  | 
 | #define WRITE_DISPLAY_TEST_CONTENT(errno, expected)                                                \ | 
 |   data().set_check_bytes();                                                                        \ | 
 |   data().set_check_handles();                                                                      \ | 
 |   PerformDisplayTest("$plt(zx_channel_write)",                                                     \ | 
 |                      ZxChannelWrite(errno, #errno, kHandle, 0, data().bytes(), data().num_bytes(), \ | 
 |                                     data().handles(), data().num_handles()),                       \ | 
 |                      expected) | 
 |  | 
 | #define WRITE_DISPLAY_TEST(name, errno, expected)                                            \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) { WRITE_DISPLAY_TEST_CONTENT(errno, expected); } \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) { WRITE_DISPLAY_TEST_CONTENT(errno, expected); } | 
 |  | 
 | WRITE_DISPLAY_TEST(ZxChannelWrite, ZX_OK, | 
 |                    "\n" | 
 |                    "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_write(" | 
 |                    "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                    "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |                    "" | 
 |                    "  \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                    "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                    "    data=\n" | 
 |                    "      0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                    ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                    "    handles=\n" | 
 |                    "      0000: 01234567, 89abcdef\n" | 
 |                    "  -> \x1B[32mZX_OK\x1B[0m\n"); | 
 |  | 
 | WRITE_DISPLAY_TEST(ZxChannelWritePeerClosed, ZX_ERR_PEER_CLOSED, | 
 |                    "\n" | 
 |                    "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_write(" | 
 |                    "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                    "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |                    "" | 
 |                    "  \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                    "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                    "    data=\n" | 
 |                    "      0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                    ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                    "    handles=\n" | 
 |                    "      0000: 01234567, 89abcdef\n" | 
 |                    "  -> \x1B[31mZX_ERR_PEER_CLOSED\x1B[0m\n"); | 
 |  | 
 | #define LARGE_WRITE_DISPLAY_TEST_CONTENT(errno, expected)                                       \ | 
 |   PerformDisplayTest(                                                                           \ | 
 |       "$plt(zx_channel_write)",                                                                 \ | 
 |       ZxChannelWrite(errno, #errno, kHandle, 0, data().large_bytes(), data().num_large_bytes(), \ | 
 |                      data().handles(), data().num_handles()),                                   \ | 
 |       expected) | 
 |  | 
 | #define LARGE_WRITE_DISPLAY_TEST(name, errno, expected)                                            \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) { LARGE_WRITE_DISPLAY_TEST_CONTENT(errno, expected); } \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) { LARGE_WRITE_DISPLAY_TEST_CONTENT(errno, expected); } | 
 |  | 
 | LARGE_WRITE_DISPLAY_TEST(ZxChannelWriteLarge, ZX_OK, | 
 |                          "\n" | 
 |                          "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_write(" | 
 |                          "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                          "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m)\n" | 
 |                          "" | 
 |                          "  \x1B[31mCan't decode message: num_bytes=100 num_handles=2 txid=9040100 " | 
 |                          "ordinal=e1c4a99079645140\x1B[0m\n" | 
 |                          "    data=\n" | 
 |                          "      0000: \x1B[31m00, 01, 04, 09\x1B[0m, 10, 19, 24, 31\x1B[31m, " | 
 |                          "40, 51, 64, 79\x1B[0m, 90, a9, c4, e1, \n" | 
 |                          "      0010: \x1B[31m00, 21, 44, 69\x1B[0m, 90, b9, e4, 11\x1B[31m, " | 
 |                          "40, 71, a4, d9\x1B[0m, 10, 49, 84, c1, \n" | 
 |                          "      0020: \x1B[31m00, 41, 84, c9\x1B[0m, 10, 59, a4, f1\x1B[31m, " | 
 |                          "40, 91, e4, 39\x1B[0m, 90, e9, 44, a1, \n" | 
 |                          "      0030: \x1B[31m00, 61, c4, 29\x1B[0m, 90, f9, 64, d1\x1B[31m, " | 
 |                          "40, b1, 24, 99\x1B[0m, 10, 89, 04, 81, \n" | 
 |                          "      0040: \x1B[31m00, 81, 04, 89\x1B[0m, 10, 99, 24, b1\x1B[31m, " | 
 |                          "40, d1, 64, f9\x1B[0m, 90, 29, c4, 61, \n" | 
 |                          "      0050: \x1B[31m00, a1, 44, e9\x1B[0m, 90, 39, e4, 91\x1B[31m, " | 
 |                          "40, f1, a4, 59\x1B[0m, 10, c9, 84, 41, \n" | 
 |                          "      0060: \x1B[31m00, c1, 84, 49\x1B[0m\n" | 
 |                          "    handles=\n" | 
 |                          "      0000: 01234567, 89abcdef\n" | 
 |                          "  -> \x1B[32mZX_OK\x1B[0m\n"); | 
 |  | 
 | #define WRITE_ABORTED_TEST_CONTENT(errno, expected)                                                \ | 
 |   PerformAbortedTest("$plt(zx_channel_write)",                                                     \ | 
 |                      ZxChannelWrite(errno, #errno, kHandle, 0, data().bytes(), data().num_bytes(), \ | 
 |                                     data().handles(), data().num_handles()),                       \ | 
 |                      expected) | 
 |  | 
 | #define WRITE_ABORTED_TEST(name, errno, expected)    \ | 
 |   TEST_F(InterceptionWorkflowTestX64Aborted, name) { \ | 
 |     WRITE_ABORTED_TEST_CONTENT(errno, expected);     \ | 
 |   }                                                  \ | 
 |   TEST_F(InterceptionWorkflowTestArmAborted, name) { WRITE_ABORTED_TEST_CONTENT(errno, expected); } | 
 |  | 
 | WRITE_ABORTED_TEST(ZxChannelWriteAborted, ZX_OK, | 
 |                    "\x1B[32m\nStop monitoring \x1B[34mtest_3141\x1B[0m koid=\x1B[31m3141\x1B[0m\n"); | 
 |  | 
 | // zx_channel_read tests. | 
 |  | 
 | std::unique_ptr<SystemCallTest> ZxChannelRead(int64_t result, std::string_view result_name, | 
 |                                               zx_handle_t handle, uint32_t options, | 
 |                                               const uint8_t* bytes, const zx_handle_t* handles, | 
 |                                               uint32_t num_bytes, uint32_t num_handles, | 
 |                                               uint32_t* actual_bytes, uint32_t* actual_handles) { | 
 |   auto value = std::make_unique<SystemCallTest>("zx_channel_read", result, result_name); | 
 |   value->AddInput(handle); | 
 |   value->AddInput(options); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(bytes)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(handles)); | 
 |   value->AddInput(num_bytes); | 
 |   value->AddInput(num_handles); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_bytes)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_handles)); | 
 |   return value; | 
 | } | 
 |  | 
 | #define READ_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected)                  \ | 
 |   if (check_bytes) {                                                                            \ | 
 |     data().set_check_bytes();                                                                   \ | 
 |   }                                                                                             \ | 
 |   if (check_handles) {                                                                          \ | 
 |     data().set_check_handles();                                                                 \ | 
 |   }                                                                                             \ | 
 |   uint32_t actual_bytes = data().num_bytes();                                                   \ | 
 |   uint32_t actual_handles = data().num_handles();                                               \ | 
 |   PerformDisplayTest("$plt(zx_channel_read)",                                                   \ | 
 |                      ZxChannelRead(errno, #errno, kHandle, 0, data().bytes(), data().handles(), \ | 
 |                                    100, 64, (check_bytes) ? &actual_bytes : nullptr,            \ | 
 |                                    (check_handles) ? &actual_handles : nullptr),                \ | 
 |                      expected); | 
 |  | 
 | #define READ_DISPLAY_TEST(name, errno, check_bytes, check_handles, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {                                \ | 
 |     READ_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   }                                                                          \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {                                \ | 
 |     READ_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   } | 
 |  | 
 | READ_DISPLAY_TEST(ZxChannelRead, ZX_OK, true, true, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                   "    \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                   "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                   "      data=\n" | 
 |                   "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                   ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                   "      handles=\n" | 
 |                   "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | READ_DISPLAY_TEST(ZxChannelReadShouldWait, ZX_ERR_SHOULD_WAIT, true, true, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  -> \x1B[31mZX_ERR_SHOULD_WAIT\x1B[0m\n"); | 
 |  | 
 | READ_DISPLAY_TEST(ZxChannelReadTooSmall, ZX_ERR_BUFFER_TOO_SMALL, true, true, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  -> \x1B[31mZX_ERR_BUFFER_TOO_SMALL\x1B[0m (" | 
 |                   "actual_bytes: \x1B[32muint32\x1B[0m = \x1B[34m16\x1B[0m, " | 
 |                   "actual_handles: \x1B[32muint32\x1B[0m = \x1B[34m2\x1B[0m)\n"); | 
 |  | 
 | READ_DISPLAY_TEST(ZxChannelReadNoBytes, ZX_OK, false, true, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                   "    not enough data for message\n" | 
 |                   "    \x1B[31mCan't decode message: num_bytes=0 num_handles=2\x1B[0m\n" | 
 |                   "      data=\x1B[0m\n" | 
 |                   "      handles=\n" | 
 |                   "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | READ_DISPLAY_TEST(ZxChannelReadNoHandles, ZX_OK, true, false, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                   "    \x1B[31mCan't decode message: num_bytes=16 num_handles=0 " | 
 |                   "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                   "      data=\n" | 
 |                   "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                   ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n"); | 
 |  | 
 | // zx_channel_read_etc tests. | 
 | std::unique_ptr<SystemCallTest> ZxChannelReadEtc(int64_t result, std::string_view result_name, | 
 |                                                  zx_handle_t handle, uint32_t options, | 
 |                                                  const uint8_t* bytes, | 
 |                                                  const zx_handle_info_t* handles, | 
 |                                                  uint32_t num_bytes, uint32_t num_handles, | 
 |                                                  uint32_t* actual_bytes, uint32_t* actual_handles) { | 
 |   auto value = std::make_unique<SystemCallTest>("zx_channel_read_etc", result, result_name); | 
 |   value->AddInput(handle); | 
 |   value->AddInput(options); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(bytes)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(handles)); | 
 |   value->AddInput(num_bytes); | 
 |   value->AddInput(num_handles); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_bytes)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_handles)); | 
 |   return value; | 
 | } | 
 |  | 
 | #define READ_ETC_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected)                \ | 
 |   if (check_bytes) {                                                                              \ | 
 |     data().set_check_bytes();                                                                     \ | 
 |   }                                                                                               \ | 
 |   if (check_handles) {                                                                            \ | 
 |     data().set_check_handles();                                                                   \ | 
 |   }                                                                                               \ | 
 |   uint32_t actual_bytes = data().num_bytes();                                                     \ | 
 |   uint32_t actual_handles = data().num_handle_infos();                                            \ | 
 |   PerformDisplayTest(                                                                             \ | 
 |       "$plt(zx_channel_read_etc)",                                                                \ | 
 |       ZxChannelReadEtc(errno, #errno, kHandle, 0, data().bytes(), data().handle_infos(), 100, 64, \ | 
 |                        (check_bytes) ? &actual_bytes : nullptr,                                   \ | 
 |                        (check_handles) ? &actual_handles : nullptr),                              \ | 
 |       expected); | 
 |  | 
 | #define READ_ETC_DISPLAY_TEST(name, errno, check_bytes, check_handles, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {                                    \ | 
 |     READ_ETC_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   }                                                                              \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {                                    \ | 
 |     READ_ETC_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   } | 
 |  | 
 | READ_ETC_DISPLAY_TEST(ZxChannelReadEtc, ZX_OK, true, true, | 
 |                       "\n" | 
 |                       "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read_etc(" | 
 |                       "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                       "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                       "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                       "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                       "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                       "    \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                       "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                       "      data=\n" | 
 |                       "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                       ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                       "      handles=\n" | 
 |                       "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | READ_ETC_DISPLAY_TEST(ZxChannelReadEtcShouldWait, ZX_ERR_SHOULD_WAIT, true, true, | 
 |                       "\n" | 
 |                       "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read_etc(" | 
 |                       "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                       "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                       "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                       "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                       "  -> \x1B[31mZX_ERR_SHOULD_WAIT\x1B[0m\n"); | 
 |  | 
 | READ_ETC_DISPLAY_TEST(ZxChannelReadEtcTooSmall, ZX_ERR_BUFFER_TOO_SMALL, true, true, | 
 |                       "\n" | 
 |                       "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read_etc(" | 
 |                       "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                       "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                       "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                       "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                       "" | 
 |                       "  -> \x1B[31mZX_ERR_BUFFER_TOO_SMALL\x1B[0m (" | 
 |                       "actual_bytes: \x1B[32muint32\x1B[0m = \x1B[34m16\x1B[0m, " | 
 |                       "actual_handles: \x1B[32muint32\x1B[0m = \x1B[34m2\x1B[0m)\n"); | 
 |  | 
 | READ_ETC_DISPLAY_TEST(ZxChannelReadEtcNoBytes, ZX_OK, false, true, | 
 |                       "\n" | 
 |                       "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read_etc(" | 
 |                       "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                       "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                       "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                       "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                       "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                       "    not enough data for message\n" | 
 |                       "    \x1B[31mCan't decode message: num_bytes=0 num_handles=2\x1B[0m\n" | 
 |                       "      data=\x1B[0m\n" | 
 |                       "      handles=\n" | 
 |                       "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | READ_ETC_DISPLAY_TEST(ZxChannelReadEtcNoHandles, ZX_OK, true, false, | 
 |                       "\n" | 
 |                       "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_read_etc(" | 
 |                       "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                       "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                       "num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                       "num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                       "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                       "    \x1B[31mCan't decode message: num_bytes=16 num_handles=0 " | 
 |                       "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                       "      data=\n" | 
 |                       "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                       ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n"); | 
 |  | 
 | // zx_channel_call tests. | 
 |  | 
 | std::unique_ptr<SystemCallTest> ZxChannelCall(int64_t result, std::string_view result_name, | 
 |                                               zx_handle_t handle, uint32_t options, | 
 |                                               zx_time_t deadline, | 
 |                                               const zx_channel_call_args_t* args, | 
 |                                               uint32_t* actual_bytes, uint32_t* actual_handles) { | 
 |   auto value = std::make_unique<SystemCallTest>("zx_channel_call", result, result_name); | 
 |   value->AddInput(handle); | 
 |   value->AddInput(options); | 
 |   value->AddInput(deadline); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(args)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_bytes)); | 
 |   value->AddInput(reinterpret_cast<uint64_t>(actual_handles)); | 
 |   return value; | 
 | } | 
 |  | 
 | #define CALL_CHECK_TEST_CONTENT(errno)                                                \ | 
 |   data().set_check_bytes();                                                           \ | 
 |   data().set_check_handles();                                                         \ | 
 |   zx_channel_call_args_t args;                                                        \ | 
 |   args.wr_bytes = data().bytes();                                                     \ | 
 |   args.wr_handles = data().handles();                                                 \ | 
 |   args.rd_bytes = data().bytes();                                                     \ | 
 |   args.rd_handles = data().handles();                                                 \ | 
 |   args.wr_num_bytes = data().num_bytes();                                             \ | 
 |   args.wr_num_handles = data().num_handles();                                         \ | 
 |   args.rd_num_bytes = 100;                                                            \ | 
 |   args.rd_num_handles = 64;                                                           \ | 
 |   uint32_t actual_bytes = data().num_bytes();                                         \ | 
 |   uint32_t actual_handles = data().num_handles();                                     \ | 
 |   zx_channel_call_args_t args2;                                                       \ | 
 |   args2.wr_bytes = data().bytes2();                                                   \ | 
 |   args2.wr_handles = data().handles2();                                               \ | 
 |   args2.rd_bytes = data().bytes2();                                                   \ | 
 |   args2.rd_handles = data().handles2();                                               \ | 
 |   args2.wr_num_bytes = data().num_bytes2();                                           \ | 
 |   args2.wr_num_handles = data().num_handles2();                                       \ | 
 |   args2.rd_num_bytes = 100;                                                           \ | 
 |   args2.rd_num_handles = 64;                                                          \ | 
 |   uint32_t actual_bytes2 = data().num_bytes2();                                       \ | 
 |   uint32_t actual_handles2 = data().num_handles2();                                   \ | 
 |   PerformCheckTest("$plt(zx_channel_call)",                                           \ | 
 |                    ZxChannelCall(errno, #errno, kHandle, 0, ZX_TIME_INFINITE, &args,  \ | 
 |                                  &actual_bytes, &actual_handles),                     \ | 
 |                    ZxChannelCall(errno, #errno, kHandle, 0, ZX_TIME_INFINITE, &args2, \ | 
 |                                  &actual_bytes2, &actual_handles2)); | 
 |  | 
 | #define CALL_CHECK_TEST(name, errno)                                            \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) { CALL_CHECK_TEST_CONTENT(errno); } \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) { CALL_CHECK_TEST_CONTENT(errno); } | 
 |  | 
 | CALL_CHECK_TEST(ZxChannelCallCheck, ZX_OK); | 
 |  | 
 | #define CALL_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected)         \ | 
 |   if (check_bytes) {                                                                   \ | 
 |     data().set_check_bytes();                                                          \ | 
 |   }                                                                                    \ | 
 |   if (check_handles) {                                                                 \ | 
 |     data().set_check_handles();                                                        \ | 
 |   }                                                                                    \ | 
 |   zx_channel_call_args_t args;                                                         \ | 
 |   args.wr_bytes = data().bytes();                                                      \ | 
 |   args.wr_handles = data().handles();                                                  \ | 
 |   args.rd_bytes = data().bytes();                                                      \ | 
 |   args.rd_handles = data().handles();                                                  \ | 
 |   args.wr_num_bytes = data().num_bytes();                                              \ | 
 |   args.wr_num_handles = data().num_handles();                                          \ | 
 |   args.rd_num_bytes = 100;                                                             \ | 
 |   args.rd_num_handles = 64;                                                            \ | 
 |   uint32_t actual_bytes = data().num_bytes();                                          \ | 
 |   uint32_t actual_handles = data().num_handles();                                      \ | 
 |   PerformDisplayTest("$plt(zx_channel_call)",                                          \ | 
 |                      ZxChannelCall(errno, #errno, kHandle, 0, ZX_TIME_INFINITE, &args, \ | 
 |                                    (check_bytes) ? &actual_bytes : nullptr,            \ | 
 |                                    (check_handles) ? &actual_handles : nullptr),       \ | 
 |                      expected); | 
 |  | 
 | #define CALL_DISPLAY_TEST(name, errno, check_bytes, check_handles, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {                                \ | 
 |     CALL_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   }                                                                          \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {                                \ | 
 |     CALL_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);  \ | 
 |   } | 
 |  | 
 | CALL_DISPLAY_TEST(ZxChannelCall, ZX_OK, true, true, | 
 |                   "\n" | 
 |                   "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_call(" | 
 |                   "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                   "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                   "deadline: \x1B[32mzx.time\x1B[0m = \x1B[34mZX_TIME_INFINITE\x1B[0m, " | 
 |                   "rd_num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |                   "rd_num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |                   "  \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                   "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                   "    data=\n" | 
 |                   "      0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                   ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                   "    handles=\n" | 
 |                   "      0000: 01234567, 89abcdef\n" | 
 |                   "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                   "    \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |                   "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |                   "      data=\n" | 
 |                   "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |                   ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |                   "      handles=\n" | 
 |                   "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | #define CALL_DISPLAY_TEST_WITH_PROCESS_INFO(name, errno, check_bytes, check_handles, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {                                                  \ | 
 |     set_with_process_info();                                                                   \ | 
 |     CALL_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);                    \ | 
 |   }                                                                                            \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {                                                  \ | 
 |     set_with_process_info();                                                                   \ | 
 |     CALL_DISPLAY_TEST_CONTENT(errno, check_bytes, check_handles, expected);                    \ | 
 |   } | 
 |  | 
 | CALL_DISPLAY_TEST_WITH_PROCESS_INFO( | 
 |     ZxChannelCallWithProcessInfo, ZX_OK, true, true, | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m \n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_call(" | 
 |     "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |     "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |     "deadline: \x1B[32mzx.time\x1B[0m = \x1B[34mZX_TIME_INFINITE\x1B[0m, " | 
 |     "rd_num_bytes: \x1B[32muint32\x1B[0m = \x1B[34m100\x1B[0m, " | 
 |     "rd_num_handles: \x1B[32muint32\x1B[0m = \x1B[34m64\x1B[0m)\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "  \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |     "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "    data=\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "      0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |     ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "    handles=\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "      0000: 01234567, 89abcdef\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "    \x1B[31mCan't decode message: num_bytes=16 num_handles=2 " | 
 |     "txid=aaaaaaaa ordinal=77e4cceb00000000\x1B[0m\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "      data=\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "        0000: \x1B[31maa, aa, aa, aa\x1B[0m, 00, 00, 00, 01\x1B[31m" | 
 |     ", 00, 00, 00, 00\x1B[0m, eb, cc, e4, 77\x1B[0m\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "      handles=\n" | 
 |     "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m " | 
 |     "        0000: 01234567, 89abcdef\n"); | 
 |  | 
 | #define CALL_DISPLAY_TEST_CONTENT_NULL_ARGS(errno, expected)                                 \ | 
 |   PerformDisplayTest(                                                                        \ | 
 |       "$plt(zx_channel_call)",                                                               \ | 
 |       ZxChannelCall(errno, #errno, kHandle, 0, ZX_TIME_INFINITE, nullptr, nullptr, nullptr), \ | 
 |       expected); | 
 |  | 
 | #define CALL_DISPLAY_TEST_NULL_ARGS(name, errno, expected) \ | 
 |   TEST_F(InterceptionWorkflowTestX64, name) {              \ | 
 |     CALL_DISPLAY_TEST_CONTENT_NULL_ARGS(errno, expected);  \ | 
 |   }                                                        \ | 
 |   TEST_F(InterceptionWorkflowTestArm, name) {              \ | 
 |     CALL_DISPLAY_TEST_CONTENT_NULL_ARGS(errno, expected);  \ | 
 |   } | 
 |  | 
 | CALL_DISPLAY_TEST_NULL_ARGS(ZxChannelCallNullArgs, ZX_OK, | 
 |                             "\n" | 
 |                             "test_3141 \x1B[31m3141\x1B[0m:\x1B[31m8764\x1B[0m zx_channel_call(" | 
 |                             "handle: \x1B[32mhandle\x1B[0m = \x1B[31mcefa1db0\x1B[0m, " | 
 |                             "options: \x1B[32muint32\x1B[0m = \x1B[34m0\x1B[0m, " | 
 |                             "deadline: \x1B[32mzx.time\x1B[0m = \x1B[34mZX_TIME_INFINITE\x1B[0m, " | 
 |                             "rd_num_bytes: \x1B[32muint32\x1B[0m = \x1B[31mnull\x1B[0m, " | 
 |                             "rd_num_handles: \x1B[32muint32\x1B[0m = \x1B[31mnull\x1B[0m)\n" | 
 |                             "  not enough data for message\n" | 
 |                             "  \x1B[31mCan't decode message: num_bytes=0 num_handles=0\x1B[0m\n" | 
 |                             "    data=\x1B[0m\n" | 
 |                             "  -> \x1B[32mZX_OK\x1B[0m\n" | 
 |                             "    not enough data for message\n" | 
 |                             "    \x1B[31mCan't decode message: num_bytes=0 num_handles=0\x1B[0m\n" | 
 |                             "      data=\x1B[0m\n"); | 
 |  | 
 | }  // namespace fidlcat |