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