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