/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "DynamicInstrumentationManager.h" #include "DebugLog.h" #include #include #include #include #include #include #include #include namespace android::uprobestats::dynamic_instrumentation_manager { struct ADynamicInstrumentationManager_MethodDescriptor; typedef struct ADynamicInstrumentationManager_MethodDescriptor ADynamicInstrumentationManager_MethodDescriptor; struct ADynamicInstrumentationManager_TargetProcess; typedef struct ADynamicInstrumentationManager_TargetProcess ADynamicInstrumentationManager_TargetProcess; struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets; typedef struct ADynamicInstrumentationManager_ExecutableMethodFileOffsets ADynamicInstrumentationManager_ExecutableMethodFileOffsets; typedef ADynamicInstrumentationManager_TargetProcess *( *ADynamicInstrumentationManager_TargetProcess_create)( uid_t uid, pid_t pid, const char *processName); typedef void (*ADynamicInstrumentationManager_TargetProcess_destroy)( const ADynamicInstrumentationManager_TargetProcess *instance); typedef ADynamicInstrumentationManager_MethodDescriptor *( *ADynamicInstrumentationManager_MethodDescriptor_create)( const char *fullyQualifiedClassName, const char *methodName, const char *fullyQualifiedParameters[], unsigned int numParameters); typedef void (*ADynamicInstrumentationManager_MethodDescriptor_destroy)( const ADynamicInstrumentationManager_MethodDescriptor *instance); typedef const char *( *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath)( const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance); typedef unsigned long ( *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset)( const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance); typedef unsigned long ( *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset)( const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance); typedef void ( *ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy)( const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *instance); typedef int32_t ( *ADynamicInstrumentationManager_getExecutableMethodFileOffsets)( const ADynamicInstrumentationManager_TargetProcess &targetProcess, const ADynamicInstrumentationManager_MethodDescriptor &methodDescriptor, const ADynamicInstrumentationManager_ExecutableMethodFileOffsets **out); const char kLibandroidPath[] = "libandroid.so"; template void getLibFunction(void *handle, const char *identifier, T *out) { auto result = reinterpret_cast(dlsym(handle, identifier)); if (!result) { ALOGE("dlsym error: %s %s %s", __func__, dlerror(), identifier); assert(result); } *out = result; } std::optional getExecutableMethodFileOffsets(std::string &processName, std::string &fqcn, std::string &methodName, std::vector &fqParameters) { void *handle = dlopen(kLibandroidPath, RTLD_NOW | RTLD_LOCAL); if (!handle) { ALOGE("dlopen error: %s %s", __func__, dlerror()); return {}; } ADynamicInstrumentationManager_TargetProcess_create targetProcess_create; getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_create", &targetProcess_create); ADynamicInstrumentationManager_TargetProcess_destroy targetProcess_destroy; getLibFunction(handle, "ADynamicInstrumentationManager_TargetProcess_destroy", &targetProcess_destroy); ADynamicInstrumentationManager_MethodDescriptor_create methodDescriptor_create; getLibFunction(handle, "ADynamicInstrumentationManager_MethodDescriptor_create", &methodDescriptor_create); ADynamicInstrumentationManager_MethodDescriptor_destroy methodDescriptor_destroy; getLibFunction(handle, "ADynamicInstrumentationManager_MethodDescriptor_destroy", &methodDescriptor_destroy); ADynamicInstrumentationManager_getExecutableMethodFileOffsets getExecutableMethodFileOffsets; getLibFunction( handle, "ADynamicInstrumentationManager_getExecutableMethodFileOffsets", &getExecutableMethodFileOffsets); ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy executableMethodFileOffsets_destroy; getLibFunction( handle, "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_destroy", &executableMethodFileOffsets_destroy); ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerPath getContainerPath; getLibFunction(handle, "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_" "getContainerPath", &getContainerPath); ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getContainerOffset getContainerOffset; getLibFunction(handle, "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_" "getContainerOffset", &getContainerOffset); ADynamicInstrumentationManager_ExecutableMethodFileOffsets_getMethodOffset getMethodOffset; getLibFunction(handle, "ADynamicInstrumentationManager_ExecutableMethodFileOffsets_" "getMethodOffset", &getMethodOffset); const ADynamicInstrumentationManager_TargetProcess *targetProcess = targetProcess_create(0, 0, processName.c_str()); std::vector fqpVec; for (size_t i = 0; i < fqParameters.size(); ++i) { fqpVec.push_back(fqParameters[i].c_str()); } const ADynamicInstrumentationManager_MethodDescriptor *methodDescriptor = methodDescriptor_create(fqcn.c_str(), methodName.c_str(), fqpVec.data(), fqParameters.size()); const ADynamicInstrumentationManager_ExecutableMethodFileOffsets *offsets = nullptr; int32_t result = getExecutableMethodFileOffsets(*targetProcess, *methodDescriptor, &offsets); targetProcess_destroy(targetProcess); methodDescriptor_destroy(methodDescriptor); if (result != 0) { LOG(ERROR) << "error calling getExecutableMethodFileOffsets. result: " << result; } if (offsets == nullptr) { LOG(ERROR) << "could not find offset for " << methodName; return {}; } const char *cp = getContainerPath(offsets); std::string containerPath(cp); uint64_t containerOffset = getContainerOffset(offsets); uint64_t methodOffset = getMethodOffset(offsets); executableMethodFileOffsets_destroy(offsets); ExecutableMethodFileOffsets executableMethodFileOffsets; executableMethodFileOffsets.containerPath = containerPath; executableMethodFileOffsets.containerOffset = containerOffset; executableMethodFileOffsets.methodOffset = methodOffset; return executableMethodFileOffsets; } } // namespace android::uprobestats::dynamic_instrumentation_manager