1 /* 2 * Copyright (C) 2019 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 #ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ 18 #define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ 19 20 // C++ wrapper for the dex file external API. 21 22 #include <cstring> 23 #include <memory> 24 #include <string> 25 #include <string_view> 26 #include <utility> 27 #include <vector> 28 29 #include <android-base/macros.h> 30 31 #include "art_api/dex_file_external.h" 32 33 namespace art_api { 34 namespace dex { 35 36 // Returns true if libdexfile_external.so is already loaded. Otherwise tries to 37 // load it and returns true if successful. Otherwise returns false and sets 38 // *error_msg. If false is returned then calling any function below may abort 39 // the process. Thread safe. 40 bool TryLoadLibdexfileExternal(std::string* error_msg); 41 42 // Loads the libdexfile_external.so library and sets up function pointers. 43 // Aborts with a fatal error on any error. For internal use by the classes 44 // below. 45 void LoadLibdexfileExternal(); 46 47 // Minimal std::string look-alike for a string returned from libdexfile. 48 class DexString final { 49 public: DexString(DexString && dex_str)50 DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) { 51 dex_str.ext_string_ = MakeExtDexFileString("", 0); 52 } 53 explicit DexString(const char* str = "") ext_string_(MakeExtDexFileString (str,std::strlen (str)))54 : ext_string_(MakeExtDexFileString(str, std::strlen(str))) {} DexString(std::string_view str)55 explicit DexString(std::string_view str) 56 : ext_string_(MakeExtDexFileString(str.data(), str.size())) {} ~DexString()57 ~DexString() { g_ExtDexFileFreeString(ext_string_); } 58 59 DexString& operator=(DexString&& dex_str) noexcept { 60 std::swap(ext_string_, dex_str.ext_string_); 61 return *this; 62 } 63 data()64 const char* data() const { 65 size_t ignored; 66 return g_ExtDexFileGetString(ext_string_, &ignored); 67 } c_str()68 const char* c_str() const { return data(); } 69 size()70 size_t size() const { 71 size_t len; 72 (void)g_ExtDexFileGetString(ext_string_, &len); 73 return len; 74 } length()75 size_t length() const { return size(); } 76 string_view()77 operator std::string_view() const { 78 size_t len; 79 const char* chars = g_ExtDexFileGetString(ext_string_, &len); 80 return std::string_view(chars, len); 81 } 82 83 private: 84 friend bool TryLoadLibdexfileExternal(std::string* error_msg); 85 friend class DexFile; 86 friend bool operator==(const DexString&, const DexString&); DexString(const ExtDexFileString * ext_string)87 explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {} 88 const ExtDexFileString* ext_string_; // Owned instance. Never nullptr. 89 90 // These are initialized by TryLoadLibdexfileExternal. 91 static decltype(ExtDexFileMakeString)* g_ExtDexFileMakeString; 92 static decltype(ExtDexFileGetString)* g_ExtDexFileGetString; decltype(ExtDexFileFreeString)93 static decltype(ExtDexFileFreeString)* g_ExtDexFileFreeString; 94 95 static const struct ExtDexFileString* MakeExtDexFileString(const char* str, size_t size) { 96 if (UNLIKELY(g_ExtDexFileMakeString == nullptr)) { 97 LoadLibdexfileExternal(); 98 } 99 return g_ExtDexFileMakeString(str, size); 100 } 101 102 DISALLOW_COPY_AND_ASSIGN(DexString); 103 }; 104 105 inline bool operator==(const DexString& s1, const DexString& s2) { 106 size_t l1, l2; 107 const char* str1 = DexString::g_ExtDexFileGetString(s1.ext_string_, &l1); 108 const char* str2 = DexString::g_ExtDexFileGetString(s2.ext_string_, &l2); 109 // Use memcmp to avoid assumption about absence of null characters in the strings. 110 return l1 == l2 && !std::memcmp(str1, str2, l1); 111 } 112 113 struct MethodInfo { 114 int32_t offset; // Code offset relative to the start of the dex file header 115 int32_t len; // Code length 116 DexString name; 117 }; 118 119 inline bool operator==(const MethodInfo& s1, const MethodInfo& s2) { 120 return s1.offset == s2.offset && s1.len == s2.len && s1.name == s2.name; 121 } 122 123 // External stable API to access ordinary dex files and CompactDex. This wraps 124 // the stable C ABI and handles instance ownership. Thread-compatible but not 125 // thread-safe. 126 class DexFile { 127 public: DexFile(DexFile && dex_file)128 DexFile(DexFile&& dex_file) noexcept { 129 ext_dex_file_ = dex_file.ext_dex_file_; 130 dex_file.ext_dex_file_ = nullptr; 131 } 132 DexFile(std::unique_ptr<DexFile> & dex_file)133 explicit DexFile(std::unique_ptr<DexFile>& dex_file) noexcept { 134 ext_dex_file_ = dex_file->ext_dex_file_; 135 dex_file->ext_dex_file_ = nullptr; 136 dex_file.reset(nullptr); 137 } 138 virtual ~DexFile(); 139 140 // Interprets a chunk of memory as a dex file. As long as *size is too small, 141 // returns nullptr, sets *size to a new size to try again with, and sets 142 // *error_msg to "". That might happen repeatedly. Also returns nullptr 143 // on error in which case *error_msg is set to a nonempty string. 144 // 145 // location is a string that describes the dex file, and is preferably its 146 // path. It is mostly used to make error messages better, and may be "". 147 // 148 // The caller must retain the memory. OpenFromMemory(const void * addr,size_t * size,const std::string & location,std::string * error_msg)149 static std::unique_ptr<DexFile> OpenFromMemory(const void* addr, 150 size_t* size, 151 const std::string& location, 152 /*out*/ std::string* error_msg) { 153 if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) { 154 // Load libdexfile_external.so in this factory function, so instance 155 // methods don't need to check this. 156 LoadLibdexfileExternal(); 157 } 158 ExtDexFile* ext_dex_file; 159 const ExtDexFileString* ext_error_msg = nullptr; 160 if (g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) { 161 return std::unique_ptr<DexFile>(new DexFile(ext_dex_file)); 162 } 163 *error_msg = (ext_error_msg == nullptr) ? "" : std::string(DexString(ext_error_msg)); 164 return nullptr; 165 } 166 167 // mmaps the given file offset in the open fd and reads a dexfile from there. 168 // Returns nullptr on error in which case *error_msg is set. 169 // 170 // location is a string that describes the dex file, and is preferably its 171 // path. It is mostly used to make error messages better, and may be "". OpenFromFd(int fd,off_t offset,const std::string & location,std::string * error_msg)172 static std::unique_ptr<DexFile> OpenFromFd(int fd, 173 off_t offset, 174 const std::string& location, 175 /*out*/ std::string* error_msg) { 176 if (UNLIKELY(g_ExtDexFileOpenFromFd == nullptr)) { 177 // Load libdexfile_external.so in this factory function, so instance 178 // methods don't need to check this. 179 LoadLibdexfileExternal(); 180 } 181 ExtDexFile* ext_dex_file; 182 const ExtDexFileString* ext_error_msg = nullptr; 183 if (g_ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) { 184 return std::unique_ptr<DexFile>(new DexFile(ext_dex_file)); 185 } 186 *error_msg = std::string(DexString(ext_error_msg)); 187 return nullptr; 188 } 189 190 // Given an offset relative to the start of the dex file header, if there is a 191 // method whose instruction range includes that offset then returns info about 192 // it, otherwise returns a struct with offset == 0. MethodInfo.name receives 193 // the full function signature if with_signature is set, otherwise it gets the 194 // class and method name only. GetMethodInfoForOffset(int64_t dex_offset,bool with_signature)195 MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) { 196 ExtDexFileMethodInfo ext_method_info; 197 if (g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_, 198 dex_offset, 199 with_signature, 200 &ext_method_info)) { 201 return AbsorbMethodInfo(ext_method_info); 202 } 203 return {/*offset=*/0, /*len=*/0, /*name=*/DexString()}; 204 } 205 206 // Returns info structs about all methods in the dex file. MethodInfo.name 207 // receives the full function signature if with_signature is set, otherwise it 208 // gets the class and method name only. GetAllMethodInfos(bool with_signature)209 std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) { 210 MethodInfoVector res; 211 g_ExtDexFileGetAllMethodInfos(ext_dex_file_, 212 with_signature, 213 AddMethodInfoCallback, 214 static_cast<void*>(&res)); 215 return res; 216 } 217 218 private: 219 friend bool TryLoadLibdexfileExternal(std::string* error_msg); DexFile(ExtDexFile * ext_dex_file)220 explicit DexFile(ExtDexFile* ext_dex_file) : ext_dex_file_(ext_dex_file) {} 221 ExtDexFile* ext_dex_file_; // Owned instance. nullptr only in moved-from zombies. 222 223 typedef std::vector<MethodInfo> MethodInfoVector; 224 225 static MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info); 226 static void AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* user_data); 227 228 // These are initialized by TryLoadLibdexfileExternal. 229 static decltype(ExtDexFileOpenFromMemory)* g_ExtDexFileOpenFromMemory; 230 static decltype(ExtDexFileOpenFromFd)* g_ExtDexFileOpenFromFd; 231 static decltype(ExtDexFileGetMethodInfoForOffset)* g_ExtDexFileGetMethodInfoForOffset; 232 static decltype(ExtDexFileGetAllMethodInfos)* g_ExtDexFileGetAllMethodInfos; 233 static decltype(ExtDexFileFree)* g_ExtDexFileFree; 234 235 DISALLOW_COPY_AND_ASSIGN(DexFile); 236 }; 237 238 } // namespace dex 239 } // namespace art_api 240 241 #endif // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_ 242