1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
17 #define LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
18
19 #include <cstdint>
20 #include "helpers.h"
21 #include "method_data_accessor.h"
22 #include "class_data_accessor-inl.h"
23 #include "annotation_data_accessor.h"
24 #include "proto_data_accessor.h"
25
26 namespace ark::panda_file {
27
28 // static
GetNameId(const File & pandaFile,File::EntityId methodId)29 inline File::EntityId MethodDataAccessor::GetNameId(const File &pandaFile, File::EntityId methodId)
30 {
31 constexpr size_t SKIP_NUM = 2; // skip class_idx and proto_idx
32 auto sp = pandaFile.GetSpanFromId(methodId).SubSpan(IDX_SIZE * SKIP_NUM);
33 return File::EntityId(helpers::Read<ID_SIZE>(&sp));
34 }
35
36 // static
GetName(const File & pandaFile,File::EntityId methodId)37 inline panda_file::File::StringData MethodDataAccessor::GetName(const File &pandaFile, File::EntityId methodId)
38 {
39 return pandaFile.GetStringData(GetNameId(pandaFile, methodId));
40 }
41
42 // static
GetProtoId(const File & pandaFile,File::EntityId methodId)43 inline File::EntityId MethodDataAccessor::GetProtoId(const File &pandaFile, File::EntityId methodId)
44 {
45 constexpr size_t SKIP_NUM = 1; // skip class_idx
46 auto sp = pandaFile.GetSpanFromId(methodId).SubSpan(IDX_SIZE * SKIP_NUM);
47 auto protoIdx = helpers::Read<IDX_SIZE>(&sp);
48 return File::EntityId(pandaFile.ResolveProtoIndex(methodId, protoIdx).GetOffset());
49 }
50
51 // static
GetClassId(const File & pandaFile,File::EntityId methodId)52 inline File::EntityId MethodDataAccessor::GetClassId(const File &pandaFile, File::EntityId methodId)
53 {
54 auto sp = pandaFile.GetSpanFromId(methodId);
55 auto classIdx = helpers::Read<IDX_SIZE>(&sp);
56 return File::EntityId(pandaFile.ResolveClassIndex(methodId, classIdx).GetOffset());
57 }
58
GetName()59 inline panda_file::File::StringData MethodDataAccessor::GetName() const
60 {
61 return pandaFile_.GetStringData(GetNameId());
62 }
63
SkipCode()64 inline void MethodDataAccessor::SkipCode()
65 {
66 GetCodeId();
67 }
68
SkipSourceLang()69 inline void MethodDataAccessor::SkipSourceLang()
70 {
71 GetSourceLang();
72 }
73
SkipRuntimeAnnotations()74 inline void MethodDataAccessor::SkipRuntimeAnnotations()
75 {
76 EnumerateRuntimeAnnotations([](File::EntityId /* unused */) {});
77 }
78
SkipRuntimeParamAnnotation()79 inline void MethodDataAccessor::SkipRuntimeParamAnnotation()
80 {
81 GetRuntimeParamAnnotationId();
82 }
83
SkipDebugInfo()84 inline void MethodDataAccessor::SkipDebugInfo()
85 {
86 GetDebugInfoId();
87 }
88
SkipAnnotations()89 inline void MethodDataAccessor::SkipAnnotations()
90 {
91 EnumerateAnnotations([](File::EntityId /* unused */) {});
92 }
93
SkipParamAnnotation()94 inline void MethodDataAccessor::SkipParamAnnotation()
95 {
96 GetParamAnnotationId();
97 }
98
SkipTypeAnnotation()99 inline void MethodDataAccessor::SkipTypeAnnotation()
100 {
101 EnumerateTypeAnnotations([](File::EntityId /* unused */) {});
102 }
103
SkipRuntimeTypeAnnotation()104 inline void MethodDataAccessor::SkipRuntimeTypeAnnotation()
105 {
106 EnumerateRuntimeTypeAnnotations([](File::EntityId /* unused */) {});
107 }
108
GetCodeId()109 inline std::optional<File::EntityId> MethodDataAccessor::GetCodeId()
110 {
111 if (isExternal_) {
112 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
113 // which fails Release builds for GCC 8 and 9.
114 std::optional<File::EntityId> novalue;
115 return novalue;
116 }
117
118 return helpers::GetOptionalTaggedValue<File::EntityId>(taggedValuesSp_, MethodTag::CODE, &sourceLangSp_);
119 }
120
GetSourceLang()121 inline std::optional<SourceLang> MethodDataAccessor::GetSourceLang()
122 {
123 if (isExternal_) {
124 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
125 // which fails Release builds for GCC 8 and 9.
126 std::optional<SourceLang> novalue;
127 return novalue;
128 }
129
130 if (sourceLangSp_.data() == nullptr) {
131 SkipCode();
132 }
133
134 return helpers::GetOptionalTaggedValue<SourceLang>(sourceLangSp_, MethodTag::SOURCE_LANG, &runtimeAnnotationsSp_);
135 }
136
137 template <class Callback>
EnumerateRuntimeAnnotations(Callback cb)138 inline void MethodDataAccessor::EnumerateRuntimeAnnotations(Callback cb)
139 {
140 if (isExternal_) {
141 return;
142 }
143
144 if (runtimeAnnotationsSp_.data() == nullptr) {
145 SkipSourceLang();
146 }
147
148 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(
149 runtimeAnnotationsSp_, MethodTag::RUNTIME_ANNOTATION, cb, &runtimeParamAnnotationSp_);
150 }
151
GetRuntimeParamAnnotationId()152 inline std::optional<File::EntityId> MethodDataAccessor::GetRuntimeParamAnnotationId()
153 {
154 if (isExternal_) {
155 return {};
156 }
157
158 if (runtimeParamAnnotationSp_.data() == nullptr) {
159 SkipRuntimeAnnotations();
160 }
161
162 return helpers::GetOptionalTaggedValue<File::EntityId>(runtimeParamAnnotationSp_,
163 MethodTag::RUNTIME_PARAM_ANNOTATION, &debugSp_);
164 }
165
GetDebugInfoId()166 inline std::optional<File::EntityId> MethodDataAccessor::GetDebugInfoId()
167 {
168 if (isExternal_) {
169 return {};
170 }
171
172 if (debugSp_.data() == nullptr) {
173 SkipRuntimeParamAnnotation();
174 }
175
176 return helpers::GetOptionalTaggedValue<File::EntityId>(debugSp_, MethodTag::DEBUG_INFO, &annotationsSp_);
177 }
178
179 template <class Callback>
EnumerateAnnotations(Callback cb)180 inline void MethodDataAccessor::EnumerateAnnotations(Callback cb)
181 {
182 if (isExternal_) {
183 return;
184 }
185
186 if (annotationsSp_.data() == nullptr) {
187 SkipDebugInfo();
188 }
189
190 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(annotationsSp_, MethodTag::ANNOTATION, cb,
191 ¶mAnnotationSp_);
192 }
193
194 template <class Callback>
EnumerateRuntimeAnnotationsWithEarlyStop(Callback cb)195 inline bool MethodDataAccessor::EnumerateRuntimeAnnotationsWithEarlyStop(Callback cb)
196 {
197 if (isExternal_) {
198 return false;
199 }
200
201 if (runtimeAnnotationsSp_.data() == nullptr) {
202 SkipSourceLang();
203 }
204
205 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, MethodTag, Callback>(
206 runtimeAnnotationsSp_, MethodTag::RUNTIME_ANNOTATION, cb);
207 }
208
209 template <class Callback>
EnumerateAnnotationsWithEarlyStop(Callback cb)210 inline bool MethodDataAccessor::EnumerateAnnotationsWithEarlyStop(Callback cb)
211 {
212 if (isExternal_) {
213 return false;
214 }
215
216 if (annotationsSp_.data() == nullptr) {
217 SkipDebugInfo();
218 }
219
220 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, MethodTag, Callback>(annotationsSp_,
221 MethodTag::ANNOTATION, cb);
222 }
223
224 template <class Callback>
EnumerateTypeAnnotations(Callback cb)225 inline void MethodDataAccessor::EnumerateTypeAnnotations(Callback cb)
226 {
227 if (isExternal_) {
228 return;
229 }
230
231 if (typeAnnotationSp_.data() == nullptr) {
232 SkipParamAnnotation();
233 }
234
235 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(typeAnnotationSp_, MethodTag::TYPE_ANNOTATION,
236 cb, &runtimeTypeAnnotationSp_);
237 }
238
239 template <class Callback>
EnumerateRuntimeTypeAnnotations(Callback cb)240 inline void MethodDataAccessor::EnumerateRuntimeTypeAnnotations(Callback cb)
241 {
242 if (isExternal_) {
243 return;
244 }
245
246 if (runtimeTypeAnnotationSp_.data() == nullptr) {
247 SkipTypeAnnotation();
248 }
249
250 helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(
251 runtimeTypeAnnotationSp_, MethodTag::RUNTIME_TYPE_ANNOTATION, cb, &profileInfoSp_);
252 }
253
GetProfileSize()254 inline std::optional<size_t> MethodDataAccessor::GetProfileSize()
255 {
256 if (isExternal_) {
257 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
258 // which fails Release builds for GCC 8 and 9.
259 return std::nullopt;
260 }
261
262 if (profileInfoSp_.data() == nullptr) {
263 SkipRuntimeTypeAnnotation();
264 }
265 Span<const uint8_t> sp {nullptr, nullptr};
266 auto v = helpers::GetOptionalTaggedValue<uint16_t>(profileInfoSp_, MethodTag::PROFILE_INFO, &sp);
267 size_ = pandaFile_.GetIdFromPointer(sp.data()).GetOffset() - methodId_.GetOffset() + 1; // + 1 for NOTHING tag
268 return v;
269 }
270
GetParamAnnotationId()271 inline std::optional<File::EntityId> MethodDataAccessor::GetParamAnnotationId()
272 {
273 if (isExternal_) {
274 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
275 // which fails Release builds for GCC 8 and 9.
276 std::optional<File::EntityId> novalue;
277 return novalue;
278 }
279
280 if (paramAnnotationSp_.data() == nullptr) {
281 SkipAnnotations();
282 }
283
284 auto v = helpers::GetOptionalTaggedValue<File::EntityId>(paramAnnotationSp_, MethodTag::PARAM_ANNOTATION,
285 &typeAnnotationSp_);
286
287 return v;
288 }
289
GetAnnotationsNumber()290 inline uint32_t MethodDataAccessor::GetAnnotationsNumber()
291 {
292 size_t n = 0;
293 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
294 return n;
295 }
296
GetRuntimeAnnotationsNumber()297 inline uint32_t MethodDataAccessor::GetRuntimeAnnotationsNumber()
298 {
299 size_t n = 0;
300 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
301 return n;
302 }
303
GetTypeAnnotationsNumber()304 inline uint32_t MethodDataAccessor::GetTypeAnnotationsNumber()
305 {
306 size_t n = 0;
307 EnumerateTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
308 return n;
309 }
310
GetRuntimeTypeAnnotationsNumber()311 inline uint32_t MethodDataAccessor::GetRuntimeTypeAnnotationsNumber()
312 {
313 size_t n = 0;
314 EnumerateRuntimeTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
315 return n;
316 }
317
318 template <typename Callback>
EnumerateTypesInProto(Callback cb,bool skipThis)319 void MethodDataAccessor::EnumerateTypesInProto(Callback cb, bool skipThis)
320 {
321 size_t refIdx = 0;
322 panda_file::ProtoDataAccessor pda(GetPandaFile(), GetProtoId());
323
324 auto type = pda.GetReturnType();
325 panda_file::File::EntityId classId;
326
327 if (!type.IsPrimitive()) {
328 classId = pda.GetReferenceType(refIdx++);
329 }
330
331 cb(type, classId);
332
333 if (!IsStatic() && !skipThis) {
334 // first arg type is method class
335 cb(panda_file::Type {panda_file::Type::TypeId::REFERENCE}, GetClassId());
336 }
337
338 for (uint32_t idx = 0; idx < pda.GetNumArgs(); ++idx) {
339 auto argType = pda.GetArgType(idx);
340 panda_file::File::EntityId klassId;
341 if (!argType.IsPrimitive()) {
342 klassId = pda.GetReferenceType(refIdx++);
343 }
344 cb(argType, klassId);
345 }
346 }
347
GetReturnType()348 inline Type MethodDataAccessor::GetReturnType() const
349 {
350 panda_file::ProtoDataAccessor pda(GetPandaFile(), GetProtoId());
351 return pda.GetReturnType();
352 }
353
354 template <std::size_t SIZE>
NumAnnonationProcess(uint32_t & result,File::EntityId & annotationId,std::array<const char *,SIZE> elemNameTable,uint32_t fieldId)355 void MethodDataAccessor::NumAnnonationProcess(uint32_t &result, File::EntityId &annotationId,
356 std::array<const char *, SIZE> elemNameTable, uint32_t fieldId)
357 {
358 AnnotationDataAccessor ada(pandaFile_, annotationId);
359 auto *annotationName = reinterpret_cast<const char *>(pandaFile_.GetStringData(ada.GetClassId()).data);
360 if (::strcmp("L_ESAnnotation;", annotationName) != 0) {
361 return;
362 }
363 uint32_t elemCount = ada.GetCount();
364 for (uint32_t i = 0; i < elemCount; i++) {
365 AnnotationDataAccessor::Elem adae = ada.GetElement(i);
366 auto *elemName = reinterpret_cast<const char *>(pandaFile_.GetStringData(adae.GetNameId()).data);
367 if (::strcmp(elemNameTable[fieldId], elemName) == 0) {
368 result = adae.GetScalarValue().GetValue();
369 }
370 }
371 }
372
GetNumericalAnnotation(uint32_t fieldId)373 inline uint32_t MethodDataAccessor::GetNumericalAnnotation(uint32_t fieldId)
374 {
375 static constexpr uint32_t NUM_ELEMENT = 3;
376 static std::array<const char *, NUM_ELEMENT> elemNameTable = {"icSize", "parameterLength", "funcName"};
377 uint32_t result = 0;
378 EnumerateAnnotations(
379 [&](File::EntityId annotationId) { NumAnnonationProcess(result, annotationId, elemNameTable, fieldId); });
380 return result;
381 }
GetClassName()382 inline std::string MethodDataAccessor::GetClassName() const
383 {
384 return panda_file::ClassDataAccessor::DemangledName(pandaFile_.GetStringData(GetClassId()));
385 }
386
GetFullName()387 inline std::string MethodDataAccessor::GetFullName() const
388 {
389 uint32_t strOffset = const_cast<MethodDataAccessor *>(this)->GetNumericalAnnotation(AnnotationField::FUNCTION_NAME);
390 if (strOffset != 0) {
391 auto mname = utf::Mutf8AsCString(pandaFile_.GetStringData(panda_file::File::EntityId(strOffset)).data);
392 return GetClassName() + "::" + mname;
393 }
394 return utf::Mutf8AsCString(GetName().data);
395 }
396
397 } // namespace ark::panda_file
398
399 #endif // LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
400