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