1 /*
2 * Copyright (C) 2024 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 "DynamicInstrumentationManager.h"
18 #include "DebugLog.h"
19 #include <android-base/logging.h>
20 #include <android-base/scopeguard.h>
21 #include <assert.h>
22 #include <dlfcn.h>
23 #include <log/log.h>
24 #include <optional>
25 #include <string>
26 #include <vector>
27
28 namespace android::uprobestats::dynamic_instrumentation_manager {
29
30 struct ADynamicInstrumentationManager_MethodDescriptor;
31 typedef struct ADynamicInstrumentationManager_MethodDescriptor
32 ADynamicInstrumentationManager_MethodDescriptor;
33
34 struct ADynamicInstrumentationManager_TargetProcess;
35 typedef struct ADynamicInstrumentationManager_TargetProcess
36 ADynamicInstrumentationManager_TargetProcess;
37
38 struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
39 typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets
40 ADynamicInstrumentationManager_ExecutableMethodFileOffsets;
41
42 typedef ADynamicInstrumentationManager_TargetProcess *(
43 *ADynamicInstrumentationManager_TargetProcess_create)(
44 uid_t uid, pid_t pid, const char *processName);
45 typedef void (*ADynamicInstrumentationManager_TargetProcess_destroy)(
46 const ADynamicInstrumentationManager_TargetProcess *instance);
47
48 typedef ADynamicInstrumentationManager_MethodDescriptor *(
49 *ADynamicInstrumentationManager_MethodDescriptor_create)(
50 const char *fullyQualifiedClassName, const char *methodName,
51 const char *fullyQualifiedParameters[], unsigned int numParameters);
52 typedef void (*ADynamicInstrumentationManager_MethodDescriptor_destroy)(
53 const ADynamicInstrumentationManager_MethodDescriptor *instance);
54
55 typedef const char *(
56 *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath)(
57 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
58 typedef unsigned long (
59 *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset)(
60 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
61 typedef unsigned long (
62 *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset)(
63 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
64 typedef void (
65 *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy)(
66 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance);
67
68 typedef int32_t (
69 *ADynamicInstrumentationManager_getExecutableMethodFileOffsets)(
70 const ADynamicInstrumentationManager_TargetProcess &targetProcess,
71 const ADynamicInstrumentationManager_MethodDescriptor &methodDescriptor,
72 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets **out);
73
74 const char kLibandroidPath[] = "libandroid.so";
75
76 template <typename T>
getLibFunction(void * handle,const char * identifier,T * out)77 void getLibFunction(void *handle, const char *identifier, T *out) {
78 auto result = reinterpret_cast<T>(dlsym(handle, identifier));
79 if (!result) {
80 ALOGE("dlsym error: %s %s %s", __func__, dlerror(), identifier);
81 assert(result);
82 }
83 *out = result;
84 }
85
86 std::optional<ExecutableMethodFileOffsets>
getExecutableMethodFileOffsets(std::string & processName,std::string & fqcn,std::string & methodName,std::vector<std::string> & fqParameters)87 getExecutableMethodFileOffsets(std::string &processName, std::string &fqcn,
88 std::string &methodName,
89 std::vector<std::string> &fqParameters) {
90 void *handle = dlopen(kLibandroidPath, RTLD_NOW | RTLD_LOCAL);
91 if (!handle) {
92 ALOGE("dlopen error: %s %s", __func__, dlerror());
93 return {};
94 }
95
96 ADynamicInstrumentationManager_TargetProcess_create targetProcess_create;
97 getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_create",
98 &targetProcess_create);
99 ADynamicInstrumentationManager_TargetProcess_destroy targetProcess_destroy;
100 getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_destroy",
101 &targetProcess_destroy);
102 ADynamicInstrumentationManager_MethodDescriptor_create
103 methodDescriptor_create;
104 getLibFunction(handle,
105 "ADynamicInstrumentationManager_MethodDescriptor_create",
106 &methodDescriptor_create);
107 ADynamicInstrumentationManager_MethodDescriptor_destroy
108 methodDescriptor_destroy;
109 getLibFunction(handle,
110 "ADynamicInstrumentationManager_MethodDescriptor_destroy",
111 &methodDescriptor_destroy);
112 ADynamicInstrumentationManager_getExecutableMethodFileOffsets
113 getExecutableMethodFileOffsets;
114 getLibFunction(
115 handle, "ADynamicInstrumentationManager_getExecutableMethodFileOffsets",
116 &getExecutableMethodFileOffsets);
117 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy
118 executableMethodFileOffsets_destroy;
119 getLibFunction(
120 handle,
121 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy",
122 &executableMethodFileOffsets_destroy);
123 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath
124 getContainerPath;
125 getLibFunction(handle,
126 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
127 "getContainerPath",
128 &getContainerPath);
129 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset
130 getContainerOffset;
131 getLibFunction(handle,
132 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
133 "getContainerOffset",
134 &getContainerOffset);
135 ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset
136 getMethodOffset;
137 getLibFunction(handle,
138 "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_"
139 "getMethodOffset",
140 &getMethodOffset);
141
142 const ADynamicInstrumentationManager_TargetProcess *targetProcess =
143 targetProcess_create(0, 0, processName.c_str());
144
145 std::vector<const char *> fqpVec;
146 for (size_t i = 0; i < fqParameters.size(); ++i) {
147 fqpVec.push_back(fqParameters[i].c_str());
148 }
149 const ADynamicInstrumentationManager_MethodDescriptor *methodDescriptor =
150 methodDescriptor_create(fqcn.c_str(), methodName.c_str(), fqpVec.data(),
151 fqParameters.size());
152
153 const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *offsets =
154 nullptr;
155 int32_t result = getExecutableMethodFileOffsets(*targetProcess,
156 *methodDescriptor, &offsets);
157
158 targetProcess_destroy(targetProcess);
159 methodDescriptor_destroy(methodDescriptor);
160
161 if (result != 0) {
162 LOG(ERROR) << "error calling getExecutableMethodFileOffsets. result: "
163 << result;
164 }
165
166 if (offsets == nullptr) {
167 LOG(ERROR) << "could not find offset for " << methodName;
168 return {};
169 }
170
171 const char *cp = getContainerPath(offsets);
172 std::string containerPath(cp);
173 uint64_t containerOffset = getContainerOffset(offsets);
174 uint64_t methodOffset = getMethodOffset(offsets);
175
176 executableMethodFileOffsets_destroy(offsets);
177
178 ExecutableMethodFileOffsets executableMethodFileOffsets;
179 executableMethodFileOffsets.containerPath = containerPath;
180 executableMethodFileOffsets.containerOffset = containerOffset;
181 executableMethodFileOffsets.methodOffset = methodOffset;
182 return executableMethodFileOffsets;
183 }
184 } // namespace android::uprobestats::dynamic_instrumentation_manager
185