1 /**
2 * Copyright (c) 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 #include "abc_file_processor.h"
17 #include <iostream>
18 #include "abc_class_processor.h"
19 #include "abc2program_log.h"
20 #include "abc_file_utils.h"
21
22 #include "abc_literal_array_processor.h"
23 #include "abc_method_processor.h"
24 #include "get_language_specific_metadata.inc"
25 #include "mangling.h"
26
27 namespace ark::abc2program {
28
AbcFileProcessor(Abc2ProgramKeyData & keyData)29 AbcFileProcessor::AbcFileProcessor(Abc2ProgramKeyData &keyData) : keyData_(keyData)
30 {
31 file_ = &(keyData_.GetAbcFile());
32 stringTable_ = &(keyData_.GetAbcStringTable());
33 program_ = &(keyData_.GetProgram());
34 }
35
ProcessFile()36 bool AbcFileProcessor::ProcessFile()
37 {
38 ProcessClasses();
39 FillLiteralArrays();
40 FillProgramStrings();
41 FillExternalFieldsToRecords();
42 GetLanguageSpecificMetadata();
43 program_->lang = keyData_.GetFileLanguage();
44 return true;
45 }
46
FillLiteralArrays()47 void AbcFileProcessor::FillLiteralArrays()
48 {
49 AbcLiteralArrayProcessor litArrayProcessor(file_->GetLiteralArraysId(), keyData_);
50 }
51
ProcessClasses()52 void AbcFileProcessor::ProcessClasses()
53 {
54 const auto classes = file_->GetClasses();
55 for (size_t i = 0; i < classes.size(); i++) {
56 uint32_t classIdx = classes[i];
57 auto classOff = file_->GetHeader()->classIdxOff + sizeof(uint32_t) * i;
58 if (classIdx > file_->GetHeader()->fileSize) {
59 LOG(FATAL, ABC2PROGRAM) << "> error encountered in record at " << classOff << " (0x" << std::hex << classOff
60 << "). binary file corrupted. record offset (0x" << classIdx
61 << ") out of bounds (0x" << file_->GetHeader()->fileSize << ")!";
62 break;
63 }
64 panda_file::File::EntityId recordId(classIdx);
65 auto language = GetRecordLanguage(recordId);
66 if (language != keyData_.GetFileLanguage()) {
67 if (keyData_.GetFileLanguage() == panda_file::SourceLang::PANDA_ASSEMBLY) {
68 keyData_.SetFileLanguage(language);
69 } else if (language != panda_file::SourceLang::PANDA_ASSEMBLY) {
70 LOG(ERROR, ABC2PROGRAM) << "> possible error encountered in record at" << classOff << " (0x" << std::hex
71 << classOff << "). record's language ("
72 << panda_file::LanguageToString(language) << ") differs from file's language ("
73 << panda_file::LanguageToString(keyData_.GetFileLanguage()) << ")!";
74 }
75 }
76 AbcClassProcessor classProcessor(recordId, keyData_);
77 }
78 }
79
FillProgramStrings()80 void AbcFileProcessor::FillProgramStrings()
81 {
82 program_->strings = stringTable_->GetStringSet();
83 }
84
FillExternalFieldsToRecords()85 void AbcFileProcessor::FillExternalFieldsToRecords()
86 {
87 for (auto &[recordName, record] : program_->recordTable) {
88 auto it = keyData_.GetExternalFieldTable().find(recordName);
89 if (it == keyData_.GetExternalFieldTable().end()) {
90 continue;
91 }
92 auto &[unused, fieldList] = *it;
93 (void)unused;
94 if (fieldList.empty()) {
95 continue;
96 }
97 for (auto &fieldIter : fieldList) {
98 if (!fieldIter.name.empty()) {
99 record.fieldList.push_back(std::move(fieldIter));
100 }
101 }
102 keyData_.GetExternalFieldTable().erase(recordName);
103 }
104 }
105
AnnotationTagToString(const char tag) const106 std::string AbcFileProcessor::AnnotationTagToString(const char tag) const
107 {
108 static const std::unordered_map<char, std::string> TAG_TO_STRING = {{'1', "u1"},
109 {'2', "i8"},
110 {'3', "u8"},
111 {'4', "i16"},
112 {'5', "u16"},
113 {'6', "i32"},
114 {'7', "u32"},
115 {'8', "i64"},
116 {'9', "u64"},
117 {'A', "f32"},
118 {'B', "f64"},
119 {'C', "string"},
120 {'D', "record"},
121 {'E', "method"},
122 {'F', "enum"},
123 {'G', "annotation"},
124 {'J', "method_handle"},
125 {'H', "array"},
126 {'K', "u1[]"},
127 {'L', "i8[]"},
128 {'M', "u8[]"},
129 {'N', "i16[]"},
130 {'O', "u16[]"},
131 {'P', "i32[]"},
132 {'Q', "u32[]"},
133 {'R', "i64[]"},
134 {'S', "u64[]"},
135 {'T', "f32[]"},
136 {'U', "f64[]"},
137 {'V', "string[]"},
138 {'W', "record[]"},
139 {'X', "method[]"},
140 {'Y', "enum[]"},
141 {'Z', "annotation[]"},
142 {'@', "method_handle[]"},
143 {'*', "nullptr_string"}};
144
145 return TAG_TO_STRING.at(tag);
146 }
147
ScalarValueToString(const panda_file::ScalarValue & value,const std::string & type)148 std::string AbcFileProcessor::ScalarValueToString(const panda_file::ScalarValue &value, const std::string &type)
149 {
150 std::stringstream ss;
151
152 if (type == "i8") {
153 auto res = value.Get<int8_t>();
154 ss << static_cast<int>(res);
155 } else if (type == "u1" || type == "u8") {
156 auto res = value.Get<uint8_t>();
157 ss << static_cast<unsigned int>(res);
158 } else if (type == "i16") {
159 ss << value.Get<int16_t>();
160 } else if (type == "u16") {
161 ss << value.Get<uint16_t>();
162 } else if (type == "i32") {
163 ss << value.Get<int32_t>();
164 } else if (type == "u32") {
165 ss << value.Get<uint32_t>();
166 } else if (type == "i64") {
167 ss << value.Get<int64_t>();
168 } else if (type == "u64") {
169 ss << value.Get<uint64_t>();
170 } else if (type == "f32") {
171 ss << value.Get<float>();
172 } else if (type == "f64") {
173 ss << value.Get<double>();
174 } else if (type == "string") {
175 const auto id = value.Get<panda_file::File::EntityId>();
176 ss << "\"" << stringTable_->GetStringById(id) << "\"";
177 } else if (type == "record") {
178 const auto id = value.Get<panda_file::File::EntityId>();
179 ss << keyData_.GetFullRecordNameById(id);
180 } else if (type == "method") {
181 const auto id = value.Get<panda_file::File::EntityId>();
182 AbcMethodProcessor methodProcessor(id, keyData_);
183 ss << methodProcessor.GetMethodSignature();
184 } else if (type == "enum") {
185 const auto id = value.Get<panda_file::File::EntityId>();
186 panda_file::FieldDataAccessor fieldAccessor(*file_, id);
187 ss << keyData_.GetFullRecordNameById(fieldAccessor.GetClassId()) << "."
188 << stringTable_->GetStringById(fieldAccessor.GetNameId());
189 } else if (type == "annotation") {
190 const auto id = value.Get<panda_file::File::EntityId>();
191 ss << "id_" << id;
192 } else if (type == "void") {
193 return std::string();
194 } else if (type == "method_handle") {
195 } else if (type == "nullptr_string") {
196 ss << static_cast<uint32_t>(0);
197 }
198
199 return ss.str();
200 }
201
ArrayValueToString(const panda_file::ArrayValue & value,const std::string & type,const size_t idx)202 std::string AbcFileProcessor::ArrayValueToString(const panda_file::ArrayValue &value, const std::string &type,
203 const size_t idx)
204 {
205 std::stringstream ss;
206
207 if (type == "i8") {
208 auto res = value.Get<int8_t>(idx);
209 ss << (static_cast<int>(res));
210 } else if (type == "u1" || type == "u8") {
211 auto res = value.Get<uint8_t>(idx);
212 ss << (static_cast<unsigned int>(res));
213 } else if (type == "i16") {
214 ss << (value.Get<int16_t>(idx));
215 } else if (type == "u16") {
216 ss << (value.Get<uint16_t>(idx));
217 } else if (type == "i32") {
218 ss << (value.Get<int32_t>(idx));
219 } else if (type == "u32") {
220 ss << (value.Get<uint32_t>(idx));
221 } else if (type == "i64") {
222 ss << (value.Get<int64_t>(idx));
223 } else if (type == "u64") {
224 ss << (value.Get<uint64_t>(idx));
225 } else if (type == "f32") {
226 ss << (value.Get<float>(idx));
227 } else if (type == "f64") {
228 ss << (value.Get<double>(idx));
229 } else if (type == "string") {
230 const auto id = value.Get<panda_file::File::EntityId>(idx);
231 ss << ('\"') << (stringTable_->GetStringById(id)) << ('\"');
232 } else if (type == "record") {
233 const auto id = value.Get<panda_file::File::EntityId>(idx);
234 ss << (keyData_.GetFullRecordNameById(id));
235 } else if (type == "method") {
236 const auto id = value.Get<panda_file::File::EntityId>(idx);
237 AbcMethodProcessor methodProcessor(id, keyData_);
238 ss << (methodProcessor.GetMethodSignature());
239 } else if (type == "enum") {
240 const auto id = value.Get<panda_file::File::EntityId>(idx);
241 panda_file::FieldDataAccessor fieldAccessor(*file_, id);
242 ss << keyData_.GetFullRecordNameById(fieldAccessor.GetClassId()) << "."
243 << stringTable_->GetStringById(fieldAccessor.GetNameId());
244 } else if (type == "annotation") {
245 const auto id = value.Get<panda_file::File::EntityId>(idx);
246 ss << ("id_") << (id);
247 } else if (type == "method_handle") {
248 } else if (type == "nullptr_string") {
249 }
250
251 return ss.str();
252 }
253
GetRecordLanguage(panda_file::File::EntityId classId) const254 ark::panda_file::SourceLang AbcFileProcessor::GetRecordLanguage(panda_file::File::EntityId classId) const
255 {
256 if (file_->IsExternal(classId)) {
257 return ark::panda_file::SourceLang::PANDA_ASSEMBLY;
258 }
259
260 panda_file::ClassDataAccessor cda(*file_, classId);
261 return cda.GetSourceLang().value_or(panda_file::SourceLang::PANDA_ASSEMBLY);
262 }
263
264 } // namespace ark::abc2program
265