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