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 <memory>
23 #include <string>
24 
25 #include "art_api/dex_file_external.h"
26 
27 namespace art_api {
28 namespace dex {
29 
30 #define FOR_EACH_ADEX_FILE_SYMBOL(MACRO) \
31   MACRO(ADexFile_Error_toString) \
32   MACRO(ADexFile_Method_getClassDescriptor) \
33   MACRO(ADexFile_Method_getCodeOffset) \
34   MACRO(ADexFile_Method_getName) \
35   MACRO(ADexFile_Method_getQualifiedName) \
36   MACRO(ADexFile_create) \
37   MACRO(ADexFile_destroy) \
38   MACRO(ADexFile_findMethodAtOffset) \
39   MACRO(ADexFile_forEachMethod) \
40 
41 #define DEFINE_ADEX_FILE_SYMBOL(DLFUNC) extern decltype(DLFUNC)* g_##DLFUNC;
42 FOR_EACH_ADEX_FILE_SYMBOL(DEFINE_ADEX_FILE_SYMBOL)
43 #undef DEFINE_ADEX_FILE_SYMBOL
44 
45 // Returns true if libdexfile.so is already loaded. Otherwise tries to
46 // load it and returns true if successful. Otherwise returns false and sets
47 // *error_msg. Thread safe.
48 bool TryLoadLibdexfile(std::string* error_msg);
49 
50 // TryLoadLibdexfile and fatally abort process if unsuccessful.
51 void LoadLibdexfile();
52 
53 // API for reading ordinary dex files and CompactDex files.
54 // It is minimal 1:1 C++ wrapper around the C ABI.
55 // See documentation in dex_file_external.h
56 class DexFile {
57  public:
58   struct Method {
59     size_t GetCodeOffset(size_t* out_size = nullptr) const {
60       return g_ADexFile_Method_getCodeOffset(self, out_size);
61     }
62 
63     const char* GetName(size_t* out_size = nullptr) const {
64       return g_ADexFile_Method_getName(self, out_size);
65     }
66 
67     const char* GetQualifiedName(bool with_params = false, size_t* out_size = nullptr) const {
68       return g_ADexFile_Method_getQualifiedName(self, with_params, out_size);
69     }
70 
71     const char* GetClassDescriptor(size_t* out_size = nullptr) const {
72       return g_ADexFile_Method_getClassDescriptor(self, out_size);
73     }
74 
75     const ADexFile_Method* const self;
76   };
77 
78   struct Error {
ToStringError79     const char* ToString() const {
80       return g_ADexFile_Error_toString(self);
81     }
82 
OkError83     bool Ok() const {
84       return self == ADEXFILE_ERROR_OK;
85     }
86 
CodeError87     ADexFile_Error Code() {
88       return self;
89     }
90 
91     ADexFile_Error const self;
92   };
93 
Create(const void * address,size_t size,size_t * new_size,const char * location,std::unique_ptr<DexFile> * out_dex_file)94   static Error Create(const void* address,
95                       size_t size,
96                       size_t* new_size,
97                       const char* location,
98                       /*out*/ std::unique_ptr<DexFile>* out_dex_file) {
99     LoadLibdexfile();
100     ADexFile* adex = nullptr;
101     ADexFile_Error error = g_ADexFile_create(address, size, new_size, location, &adex);
102     if (adex != nullptr) {
103       *out_dex_file = std::unique_ptr<DexFile>(new DexFile{adex});
104     }
105     return Error{error};
106   }
107 
~DexFile()108   virtual ~DexFile() {
109     g_ADexFile_destroy(self_);
110   }
111 
112   template<typename T /* lambda which takes (const DexFile::Method&) as argument */>
FindMethodAtOffset(uint32_t dex_offset,T callback)113   inline size_t FindMethodAtOffset(uint32_t dex_offset, T callback) {
114     auto cb = [](void* ctx, const ADexFile_Method* m) { (*reinterpret_cast<T*>(ctx))(Method{m}); };
115     return g_ADexFile_findMethodAtOffset(self_, dex_offset, cb, &callback);
116   }
117 
118   template<typename T /* lambda which takes (const DexFile::Method&) as argument */>
ForEachMethod(T callback)119   inline size_t ForEachMethod(T callback) {
120     auto cb = [](void* ctx, const ADexFile_Method* m) { (*reinterpret_cast<T*>(ctx))(Method{m}); };
121     return g_ADexFile_forEachMethod(self_, cb, &callback);
122   }
123 
124  protected:
DexFile(ADexFile * self)125   explicit DexFile(ADexFile* self) : self_(self) {}
126 
127   ADexFile* const self_;
128 
129   // Have to expand DISALLOW_COPY_AND_ASSIGN here, since we cannot depend on
130   // libbase headers without re-exporting them, and that may make them override
131   // the non-ABI compatible headers that the libdexfile_support user may have.
132   DexFile(const DexFile&) = delete;
133   void operator=(const DexFile&) = delete;
134 };
135 
136 }  // namespace dex
137 }  // namespace art_api
138 
139 #endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
140