1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include <pthread.h>
20 #include <sched.h>
21 #include <sys/mman.h>
22 
23 #include <cstdint>
24 #include <cstring>
25 
26 namespace {
27 
28 // Flush cache and i-cache
ClearInsnCache(void * start,void * end)29 void ClearInsnCache(void* start, void* end) {
30   // Only use __builtin___clear_cache with Clang or with GCC >= 4.3.0
31   __builtin___clear_cache(static_cast<char*>(start), static_cast<char*>(end));
32 }
33 
34 }  // namespace
35 
TEST(RuntimeCodePatching,PatchCodeInCurrentThread)36 TEST(RuntimeCodePatching, PatchCodeInCurrentThread) {
37   // The following function patches loop back branch at L2 with branch to next insn.
38   // To avoid messing with immediates, code to write is taken from L3, and helper
39   // to flush insn cache from L5.
40   const uint32_t code_image[] = {
41       0xe92d41f0,  //   push {r4, r5, r6, r7, r8, lr}
42                    // <L1>:
43       0xe59f3014,  //   ldr r3, L3
44       0xe58f300c,  //   str r3, L2
45       0xe28f0008,  //   adr r0, L2
46       0xe28f1008,  //   adr r1, L3
47       0xe59f4010,  //   ldr r4, L5
48       0xe12fff34,  //   blx r4
49                    // <L2>:
50       0xeafffff8,  //   b L1
51                    // <L3>:
52       0xeaffffff,  //   b L4
53                    // <L4>:
54       0xe3a0000b,  //   mov r0, #11
55       0xe8bd81f0,  //   pop {r4, r5, r6, r7, r8, pc}
56                    // <L5>:
57       0xe320f000,  //   nop {0}
58   };
59 
60   uint32_t* code = reinterpret_cast<uint32_t*>(
61       mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
62   memcpy(code, code_image, sizeof(code_image));
63   code[11] = reinterpret_cast<uint32_t>(ClearInsnCache);
64   // ATTENTION: flush insn cache! Otherwise just mmaped page might remain cached with wrong prot!
65   ClearInsnCache(code, code + 1024);
66 
67   using Func = int32_t (*)();
68   int32_t result = (reinterpret_cast<Func>(code))();
69   EXPECT_EQ(result, 11);
70 
71   munmap(code, 4096);
72 }
73 
TEST(RuntimeCodePatching,PatchCodeInOtherThread)74 TEST(RuntimeCodePatching, PatchCodeInOtherThread) {
75   // The following function writes 1 to address in r0 and loops. The write is
76   // needed to notify other threads that we entered the loop. We are going to
77   // patch the back branch to exit the loop.
78   const uint32_t code_image[] = {
79       0xe92d41f0,  //   push {r4, r5, r6, r7, r8, lr}
80                    // <L1>:
81       0xe3a01001,  //   mov r1, #1
82       0xe5801000,  //   str r1, [r0]
83                    // <L2>:
84       0xeafffffc,  //   b 4          // <L1>
85                    // <L4>:
86       0xe3a0000b,  //   mov r0, #11  // arbitrary return value
87       0xe8bd81f0,  //   pop {r4, r5, r6, r7, r8, pc}
88   };
89 
90   uint32_t* code = reinterpret_cast<uint32_t*>(
91       mmap(0, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
92   memcpy(code, code_image, sizeof(code_image));
93   // ATTENTION: flush insn cache! Otherwise just mmaped page might remain cached with wrong prot!
94   ClearInsnCache(code, code + 1024);
95 
96   volatile int func_thread_started = 0;
97 
98   using Func = void* (*)(void*);
99   pthread_t func_thread;
100   ASSERT_EQ(pthread_create(&func_thread,
101                            nullptr,
102                            reinterpret_cast<Func>(code),
103                            const_cast<int*>(&func_thread_started)),
104             0);
105 
106   while (!func_thread_started) {
107     sched_yield();
108   }
109 
110   code[3] = 0xeaffffff;  // overwrite loop branch with branch to next insn
111   ClearInsnCache(code + 3, code + 4);
112 
113   void* result;
114   ASSERT_EQ(pthread_join(func_thread, &result), 0);
115   EXPECT_EQ(reinterpret_cast<int>(result), 11);
116 
117   munmap(code, 4096);
118 }
119