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