• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
17 #define PANDA_LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
18 
19 #include "helpers.h"
20 #include "method_data_accessor.h"
21 #include "annotation_data_accessor.h"
22 #include "proto_data_accessor.h"
23 
24 namespace panda::panda_file {
25 
SkipCode()26 inline void MethodDataAccessor::SkipCode()
27 {
28     GetCodeId();
29 }
30 
SkipSourceLang()31 inline void MethodDataAccessor::SkipSourceLang()
32 {
33     GetSourceLang();
34 }
35 
SkipRuntimeAnnotations()36 inline void MethodDataAccessor::SkipRuntimeAnnotations()
37 {
38     EnumerateRuntimeAnnotations([](File::EntityId /* unused */) {});
39 }
40 
SkipRuntimeParamAnnotation()41 inline void MethodDataAccessor::SkipRuntimeParamAnnotation()
42 {
43     GetRuntimeParamAnnotationId();
44 }
45 
SkipDebugInfo()46 inline void MethodDataAccessor::SkipDebugInfo()
47 {
48     GetDebugInfoId();
49 }
50 
SkipAnnotations()51 inline void MethodDataAccessor::SkipAnnotations()
52 {
53     EnumerateAnnotations([](File::EntityId /* unused */) {});
54 }
55 
SkipParamAnnotation()56 inline void MethodDataAccessor::SkipParamAnnotation()
57 {
58     GetParamAnnotationId();
59 }
60 
GetCodeId()61 inline std::optional<File::EntityId> MethodDataAccessor::GetCodeId()
62 {
63     if (is_external_) {
64         // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
65         // which fails Release builds for GCC 8 and 9.
66         std::optional<File::EntityId> novalue;
67         return novalue;
68     }
69 
70     return helpers::GetOptionalTaggedValue<File::EntityId>(tagged_values_sp_, MethodTag::CODE, &source_lang_sp_);
71 }
72 
GetSourceLang()73 inline std::optional<SourceLang> MethodDataAccessor::GetSourceLang()
74 {
75     if (is_external_) {
76         // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
77         // which fails Release builds for GCC 8 and 9.
78         std::optional<SourceLang> novalue;
79         return novalue;
80     }
81 
82     if (source_lang_sp_.data() == nullptr) {
83         SkipCode();
84     }
85 
86     return helpers::GetOptionalTaggedValue<SourceLang>(source_lang_sp_, MethodTag::SOURCE_LANG,
87                                                        &runtime_annotations_sp_);
88 }
89 
90 template <class Callback>
EnumerateRuntimeAnnotations(Callback cb)91 inline void MethodDataAccessor::EnumerateRuntimeAnnotations(Callback cb)
92 {
93     if (is_external_) {
94         return;
95     }
96 
97     if (runtime_annotations_sp_.data() == nullptr) {
98         SkipSourceLang();
99     }
100 
101     helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(
102         runtime_annotations_sp_, MethodTag::RUNTIME_ANNOTATION, cb, &runtime_param_annotation_sp_);
103 }
104 
GetRuntimeParamAnnotationId()105 inline std::optional<File::EntityId> MethodDataAccessor::GetRuntimeParamAnnotationId()
106 {
107     if (is_external_) {
108         return {};
109     }
110 
111     if (runtime_param_annotation_sp_.data() == nullptr) {
112         SkipRuntimeAnnotations();
113     }
114 
115     return helpers::GetOptionalTaggedValue<File::EntityId>(runtime_param_annotation_sp_,
116                                                            MethodTag::RUNTIME_PARAM_ANNOTATION, &debug_sp_);
117 }
118 
GetDebugInfoId()119 inline std::optional<File::EntityId> MethodDataAccessor::GetDebugInfoId()
120 {
121     if (is_external_) {
122         return {};
123     }
124 
125     if (debug_sp_.data() == nullptr) {
126         SkipRuntimeParamAnnotation();
127     }
128 
129     return helpers::GetOptionalTaggedValue<File::EntityId>(debug_sp_, MethodTag::DEBUG_INFO, &annotations_sp_);
130 }
131 
132 template <class Callback>
EnumerateAnnotations(Callback cb)133 inline void MethodDataAccessor::EnumerateAnnotations(Callback cb)
134 {
135     if (is_external_) {
136         return;
137     }
138 
139     if (annotations_sp_.data() == nullptr) {
140         SkipDebugInfo();
141     }
142 
143     helpers::EnumerateTaggedValues<File::EntityId, MethodTag, Callback>(annotations_sp_, MethodTag::ANNOTATION, cb,
144                                                                         &param_annotation_sp_);
145 }
146 
GetParamAnnotationId()147 inline std::optional<File::EntityId> MethodDataAccessor::GetParamAnnotationId()
148 {
149     if (is_external_) {
150         // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
151         // which fails Release builds for GCC 8 and 9.
152         std::optional<File::EntityId> novalue;
153         return novalue;
154     }
155 
156     if (param_annotation_sp_.data() == nullptr) {
157         SkipAnnotations();
158     }
159 
160     Span<const uint8_t> sp {nullptr, nullptr};
161     auto v = helpers::GetOptionalTaggedValue<File::EntityId>(param_annotation_sp_, MethodTag::PARAM_ANNOTATION, &sp);
162 
163     size_ = panda_file_.GetIdFromPointer(sp.data()).GetOffset() - method_id_.GetOffset() + 1;  // + 1 for NOTHING tag
164 
165     return v;
166 }
167 
GetAnnotationsNumber()168 inline uint32_t MethodDataAccessor::GetAnnotationsNumber()
169 {
170     size_t n = 0;
171     EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
172     return n;
173 }
174 
GetRuntimeAnnotationsNumber()175 inline uint32_t MethodDataAccessor::GetRuntimeAnnotationsNumber()
176 {
177     size_t n = 0;
178     EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
179     return n;
180 }
181 
182 template <typename Callback>
EnumerateTypesInProto(Callback cb)183 void MethodDataAccessor::EnumerateTypesInProto(Callback cb)
184 {
185     size_t ref_idx = 0;
186     panda_file::ProtoDataAccessor pda(GetPandaFile(), GetProtoId());
187 
188     auto type = pda.GetReturnType();
189     panda_file::File::EntityId class_id;
190 
191     if (!type.IsPrimitive()) {
192         class_id = pda.GetReferenceType(ref_idx++);
193     }
194 
195     cb(type, class_id);
196 
197     if (!IsStatic()) {
198         // first arg type is method class
199         cb(panda_file::Type {panda_file::Type::TypeId::REFERENCE}, GetClassId());
200     }
201 
202     for (uint32_t idx = 0; idx < pda.GetNumArgs(); ++idx) {
203         auto arg_type = pda.GetArgType(idx);
204         panda_file::File::EntityId klass_id;
205         if (!arg_type.IsPrimitive()) {
206             klass_id = pda.GetReferenceType(ref_idx++);
207         }
208         cb(arg_type, klass_id);
209     }
210 }
211 
GetNumericalAnnotation(uint32_t field_id)212 inline uint32_t MethodDataAccessor::GetNumericalAnnotation(uint32_t field_id)
213 {
214     static constexpr uint32_t NUM_ELEMENT = 3;
215     static std::array<const char *, NUM_ELEMENT> elem_name_table = {"icSize", "parameterLength", "funcName"};
216     uint32_t result = 0;
217     EnumerateAnnotations([&](File::EntityId annotation_id) {
218         AnnotationDataAccessor ada(panda_file_, annotation_id);
219         auto *annotation_name = reinterpret_cast<const char *>(panda_file_.GetStringData(ada.GetClassId()).data);
220         if (::strcmp("L_ESAnnotation;", annotation_name) == 0) {
221             uint32_t elem_count = ada.GetCount();
222             for (uint32_t i = 0; i < elem_count; i++) {
223                 AnnotationDataAccessor::Elem adae = ada.GetElement(i);
224                 auto *elem_name = reinterpret_cast<const char *>(panda_file_.GetStringData(adae.GetNameId()).data);
225                 if (::strcmp(elem_name_table[field_id], elem_name) == 0) {
226                     result = adae.GetScalarValue().GetValue();
227                 }
228             }
229         }
230     });
231     return result;
232 }
233 
234 }  // namespace panda::panda_file
235 
236 #endif  // PANDA_LIBPANDAFILE_METHOD_DATA_ACCESSOR_INL_H_
237