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 "program_dump.h"
17 #include "mangling.h"
18 #include "method_data_accessor-inl.h"
19 #include "abc2program_log.h"
20 #include "abc_file_utils.h"
21 #include "source_language.h"
22
23 namespace ark::abc2program {
24
Dump(std::ostream & os,const pandasm::Program & program) const25 void PandasmProgramDumper::Dump(std::ostream &os, const pandasm::Program &program) const
26 {
27 os << std::flush;
28 DumpAbcFilePath(os);
29 DumpProgramLanguage(os, program);
30 DumpLiteralArrayTable(os, program);
31 DumpRecordTable(os, program);
32 DumpFunctionTable(os, program);
33 }
34
HasNoAbcInput() const35 bool PandasmProgramDumper::HasNoAbcInput() const
36 {
37 return ((file_ == nullptr) || (stringTable_ == nullptr));
38 }
39
DumpAbcFilePath(std::ostream & os) const40 void PandasmProgramDumper::DumpAbcFilePath(std::ostream &os) const
41 {
42 if (HasNoAbcInput()) {
43 return;
44 }
45 os << DUMP_TITLE_SOURCE_BINARY << file_->GetFilename() << DUMP_CONTENT_DOUBLE_ENDL;
46 }
47
DumpProgramLanguage(std::ostream & os,const pandasm::Program & program) const48 void PandasmProgramDumper::DumpProgramLanguage(std::ostream &os, const pandasm::Program &program) const
49 {
50 os << DUMP_TITLE_LANGUAGE;
51 os << ark::panda_file::LanguageToString(program.lang);
52 os << DUMP_CONTENT_DOUBLE_ENDL;
53 }
54
DumpLiteralArrayTable(std::ostream & os,const pandasm::Program & program) const55 void PandasmProgramDumper::DumpLiteralArrayTable(std::ostream &os, const pandasm::Program &program) const
56 {
57 if (HasNoAbcInput()) {
58 DumpLiteralArrayTableWithoutKey(os, program);
59 } else {
60 DumpLiteralArrayTableWithKey(os, program);
61 }
62 }
63
DumpLiteralArrayTableWithKey(std::ostream & os,const pandasm::Program & program) const64 void PandasmProgramDumper::DumpLiteralArrayTableWithKey(std::ostream &os, const pandasm::Program &program) const
65 {
66 os << DUMP_TITLE_SEPARATOR;
67 os << DUMP_TITLE_LITERALS << DUMP_CONTENT_SINGLE_ENDL;
68 for (auto &[key, litArray] : program.literalarrayTable) {
69 DumpLiteralArrayWithKey(os, key, litArray, program);
70 }
71 os << DUMP_CONTENT_DOUBLE_ENDL;
72 }
73
DumpLiteralArrayWithKey(std::ostream & os,const std::string & key,const pandasm::LiteralArray & litArray,const pandasm::Program & program) const74 void PandasmProgramDumper::DumpLiteralArrayWithKey(std::ostream &os, const std::string &key,
75 const pandasm::LiteralArray &litArray,
76 const pandasm::Program &program) const
77 {
78 os << DUMP_TITLE_LITERAL_ARRAY;
79 os << DUMP_LITERAL_ARRAY_PREFIX;
80 os << key << " ";
81 DumpLiteralArray(os, litArray, program);
82 os << DUMP_CONTENT_SINGLE_ENDL;
83 }
84
DumpLiteralArrayTableWithoutKey(std::ostream & os,const pandasm::Program & program) const85 void PandasmProgramDumper::DumpLiteralArrayTableWithoutKey(std::ostream &os, const pandasm::Program &program) const
86 {
87 for (auto &[unused, litArray] : program.literalarrayTable) {
88 (void)unused;
89 DumpLiteralArray(os, litArray, program);
90 os << DUMP_CONTENT_SINGLE_ENDL;
91 }
92 os << DUMP_CONTENT_DOUBLE_ENDL;
93 }
94
DumpRecordTable(std::ostream & os,const pandasm::Program & program) const95 void PandasmProgramDumper::DumpRecordTable(std::ostream &os, const pandasm::Program &program) const
96 {
97 os << DUMP_TITLE_SEPARATOR;
98 os << DUMP_TITLE_RECORDS;
99 os << DUMP_CONTENT_DOUBLE_ENDL;
100 for (const auto &it : program.recordTable) {
101 DumpRecord(os, it.second);
102 }
103 os << DUMP_CONTENT_SINGLE_ENDL;
104 }
105
DumpRecord(std::ostream & os,const pandasm::Record & record) const106 void PandasmProgramDumper::DumpRecord(std::ostream &os, const pandasm::Record &record) const
107 {
108 if (AbcFileUtils::IsSystemTypeName(record.name)) {
109 return;
110 }
111 os << DUMP_TITLE_RECORD << record.name;
112 if (DumpMetaData(os, *record.metadata)) {
113 DumpFieldList(os, record);
114 }
115 DumpRecordSourceFile(os, record);
116 }
117
DumpFieldList(std::ostream & os,const pandasm::Record & record) const118 void PandasmProgramDumper::DumpFieldList(std::ostream &os, const pandasm::Record &record) const
119 {
120 if (record.metadata->IsForeign() && record.fieldList.empty()) {
121 os << DUMP_CONTENT_DOUBLE_ENDL;
122 return;
123 }
124 os << " {" << DUMP_CONTENT_SINGLE_ENDL;
125 for (const auto &it : record.fieldList) {
126 DumpField(os, it);
127 os << DUMP_CONTENT_SINGLE_ENDL;
128 }
129 os << DUMP_CONTENT_SINGLE_ENDL << "}" << DUMP_CONTENT_SINGLE_ENDL;
130 }
131
DumpField(std::ostream & os,const pandasm::Field & field) const132 void PandasmProgramDumper::DumpField(std::ostream &os, const pandasm::Field &field) const
133 {
134 os << "\t" << field.type.GetPandasmName() << " " << field.name;
135 DumpMetaData(os, *field.metadata);
136 }
137
DumpMetaData(std::ostream & os,const pandasm::ItemMetadata & meta) const138 bool PandasmProgramDumper::DumpMetaData(std::ostream &os, const pandasm::ItemMetadata &meta) const
139 {
140 auto boolAttributes = meta.GetBoolAttributes();
141 auto attributes = meta.GetAttributes();
142 if (boolAttributes.empty() && attributes.empty()) {
143 return true;
144 }
145
146 os << " <";
147
148 size_t size = boolAttributes.size();
149 size_t idx = 0;
150 for (const auto &attr : boolAttributes) {
151 os << attr;
152 ++idx;
153
154 if (!attributes.empty() || idx < size) {
155 os << ", ";
156 }
157 }
158
159 size = attributes.size();
160 idx = 0;
161 for (const auto &[key, values] : attributes) {
162 for (size_t i = 0; i < values.size(); i++) {
163 os << key << "=" << values[i];
164
165 if (i < values.size() - 1) {
166 os << ", ";
167 }
168 }
169
170 ++idx;
171
172 if (idx < size) {
173 os << ", ";
174 }
175 }
176
177 os << ">";
178 return true;
179 }
180
DumpRecordSourceFile(std::ostream & os,const pandasm::Record & record) const181 void PandasmProgramDumper::DumpRecordSourceFile(std::ostream &os, const pandasm::Record &record) const
182 {
183 os << DUMP_TITLE_RECORD_SOURCE_FILE << record.sourceFile << DUMP_CONTENT_DOUBLE_ENDL;
184 }
185
DumpFunctionTable(std::ostream & os,const pandasm::Program & program) const186 void PandasmProgramDumper::DumpFunctionTable(std::ostream &os, const pandasm::Program &program) const
187 {
188 os << DUMP_TITLE_SEPARATOR;
189 os << DUMP_TITLE_METHODS;
190 os << DUMP_CONTENT_DOUBLE_ENDL;
191 for (const auto &it : program.functionTable) {
192 DumpFunction(os, it.second);
193 }
194 }
195
DumpFunction(std::ostream & os,const pandasm::Function & function) const196 void PandasmProgramDumper::DumpFunction(std::ostream &os, const pandasm::Function &function) const
197 {
198 os << DUMP_TITLE_FUNCTION;
199 os << function.returnType.GetPandasmName() << " " << function.name << "(";
200 if (!function.params.empty()) {
201 os << function.params[0].type.GetPandasmName() << " a0";
202
203 for (size_t i = 1; i < function.params.size(); i++) {
204 os << ", " << function.params[i].type.GetPandasmName() << " a" << (size_t)i;
205 }
206 }
207 os << ")";
208
209 const std::string signature = pandasm::GetFunctionSignatureFromName(function.name, function.params);
210
211 DumpMetaData(os, *function.metadata);
212
213 if (!function.HasImplementation()) {
214 os << DUMP_CONTENT_DOUBLE_ENDL;
215 return;
216 }
217
218 os << " {";
219
220 os << DUMP_CONTENT_SINGLE_ENDL;
221
222 DumpInstructions(os, function);
223
224 os << "}" << DUMP_CONTENT_DOUBLE_ENDL;
225 }
226
DumpInstructions(std::ostream & os,const pandasm::Function & function) const227 void PandasmProgramDumper::DumpInstructions(std::ostream &os, const pandasm::Function &function) const
228 {
229 for (const auto &instr : function.ins) {
230 std::string ins = instr.ToString("", function.GetParamsNum() != 0, function.regsNum);
231 if (instr.setLabel) {
232 std::string delim = ": ";
233 size_t pos = ins.find(delim);
234 std::string label = ins.substr(0, pos);
235 ins.erase(0, pos + delim.length());
236
237 os << label << ":";
238 os << DUMP_CONTENT_SINGLE_ENDL;
239 }
240
241 os << "\t";
242 os << ins;
243 os << DUMP_CONTENT_SINGLE_ENDL;
244 }
245 }
246
DumpStrings(std::ostream & os,const pandasm::Program & program) const247 void PandasmProgramDumper::DumpStrings(std::ostream &os, const pandasm::Program &program) const
248 {
249 if (HasNoAbcInput()) {
250 DumpStringsByProgram(os, program);
251 } else {
252 DumpStringsByStringTable(os, *stringTable_);
253 }
254 }
255
DumpStringsByStringTable(std::ostream & os,const AbcStringTable & stringTable) const256 void PandasmProgramDumper::DumpStringsByStringTable(std::ostream &os, const AbcStringTable &stringTable) const
257 {
258 os << DUMP_TITLE_SEPARATOR;
259 os << DUMP_TITLE_STRING;
260 stringTable.Dump(os);
261 os << DUMP_CONTENT_SINGLE_ENDL;
262 }
263
DumpStringsByProgram(std::ostream & os,const pandasm::Program & program) const264 void PandasmProgramDumper::DumpStringsByProgram(std::ostream &os, const pandasm::Program &program) const
265 {
266 os << DUMP_TITLE_SEPARATOR;
267 os << DUMP_TITLE_STRING;
268 os << DUMP_CONTENT_SINGLE_ENDL;
269 for (const std::string &str : program.strings) {
270 os << str << DUMP_CONTENT_SINGLE_ENDL;
271 }
272 os << DUMP_CONTENT_SINGLE_ENDL;
273 }
274
DumpLiteralArray(std::ostream & os,const pandasm::LiteralArray & litArray,const pandasm::Program & program) const275 void PandasmProgramDumper::DumpLiteralArray(std::ostream &os, const pandasm::LiteralArray &litArray,
276 const pandasm::Program &program) const
277 {
278 if (litArray.literals.empty()) {
279 return;
280 }
281
282 bool isConst = litArray.literals[0].IsArray();
283
284 std::stringstream specifiers {};
285 if (isConst) {
286 specifiers << LiteralTagToString(litArray.literals[0].tag, program) << " " << litArray.literals.size() << " ";
287 }
288 os << specifiers.str() << "{";
289
290 DumpValues(litArray, isConst, os, program);
291
292 os << "}" << DUMP_CONTENT_SINGLE_ENDL;
293 }
294
295 template <typename T>
LiteralIntegralValueToString(const pandasm::LiteralArray::Literal & lit)296 std::string LiteralIntegralValueToString(const pandasm::LiteralArray::Literal &lit)
297 {
298 std::stringstream res {};
299 T value = std::get<T>(lit.value);
300 if (lit.IsSigned()) {
301 res << +static_cast<typename std::make_signed<T>::type>(value);
302 } else {
303 res << +value;
304 }
305 return res.str();
306 }
307
LiteralValueToString(const pandasm::LiteralArray::Literal & lit) const308 std::string PandasmProgramDumper::LiteralValueToString(const pandasm::LiteralArray::Literal &lit) const
309 {
310 if (lit.IsBoolValue()) {
311 std::stringstream res {};
312 res << (std::get<bool>(lit.value));
313 return res.str();
314 }
315
316 if (lit.IsByteValue()) {
317 return LiteralIntegralValueToString<uint8_t>(lit);
318 }
319
320 if (lit.IsShortValue()) {
321 return LiteralIntegralValueToString<uint16_t>(lit);
322 }
323
324 if (lit.IsIntegerValue()) {
325 return LiteralIntegralValueToString<uint32_t>(lit);
326 }
327
328 if (lit.IsLongValue()) {
329 return LiteralIntegralValueToString<uint64_t>(lit);
330 }
331
332 if (lit.IsDoubleValue()) {
333 std::stringstream res {};
334 res << std::get<double>(lit.value);
335 return res.str();
336 }
337
338 if (lit.IsFloatValue()) {
339 std::stringstream res {};
340 res << std::get<float>(lit.value);
341 return res.str();
342 }
343
344 if (lit.IsStringValue()) {
345 std::stringstream res {};
346 res << "\"" << std::get<std::string>(lit.value) << "\"";
347 return res.str();
348 }
349
350 UNREACHABLE();
351 }
352
DumpValues(const pandasm::LiteralArray & litArray,const bool isConst,std::ostream & os,const pandasm::Program & program) const353 void PandasmProgramDumper::DumpValues(const pandasm::LiteralArray &litArray, const bool isConst, std::ostream &os,
354 const pandasm::Program &program) const
355 {
356 std::string separator = (isConst) ? (" ") : ("\n");
357
358 os << separator;
359
360 if (isConst) {
361 for (const auto &l : litArray.literals) {
362 os << LiteralValueToString(l) << separator;
363 }
364 } else {
365 for (const auto &l : litArray.literals) {
366 os << "\t" << LiteralTagToString(l.tag, program) << " " << LiteralValueToString(l) << separator;
367 }
368 }
369 }
370
LiteralTagToString(const panda_file::LiteralTag & tag,const pandasm::Program & program) const371 std::string PandasmProgramDumper::LiteralTagToString(const panda_file::LiteralTag &tag,
372 const pandasm::Program &program) const
373 {
374 switch (tag) {
375 case panda_file::LiteralTag::BOOL:
376 case panda_file::LiteralTag::ARRAY_U1:
377 return "u1";
378 case panda_file::LiteralTag::ARRAY_U8:
379 return "u8";
380 case panda_file::LiteralTag::ARRAY_I8:
381 return "i8";
382 case panda_file::LiteralTag::ARRAY_U16:
383 return "u16";
384 case panda_file::LiteralTag::ARRAY_I16:
385 return "i16";
386 case panda_file::LiteralTag::ARRAY_U32:
387 return "u32";
388 case panda_file::LiteralTag::INTEGER:
389 case panda_file::LiteralTag::ARRAY_I32:
390 return "i32";
391 case panda_file::LiteralTag::ARRAY_U64:
392 return "u64";
393 case panda_file::LiteralTag::BIGINT:
394 case panda_file::LiteralTag::ARRAY_I64:
395 return "i64";
396 case panda_file::LiteralTag::FLOAT:
397 case panda_file::LiteralTag::ARRAY_F32:
398 return "f32";
399 case panda_file::LiteralTag::DOUBLE:
400 case panda_file::LiteralTag::ARRAY_F64:
401 return "f64";
402 case panda_file::LiteralTag::STRING:
403 case panda_file::LiteralTag::ARRAY_STRING:
404 return pandasm::Type::FromDescriptor(panda_file::GetStringClassDescriptor(program.lang)).GetPandasmName();
405 case panda_file::LiteralTag::ACCESSOR:
406 return "accessor";
407 case panda_file::LiteralTag::NULLVALUE:
408 return "nullvalue";
409 case panda_file::LiteralTag::METHODAFFILIATE:
410 return "method_affiliate";
411 case panda_file::LiteralTag::METHOD:
412 return "method";
413 case panda_file::LiteralTag::GENERATORMETHOD:
414 return "generator_method";
415 default:
416 LOG(ERROR, ABC2PROGRAM) << "Unsupported literal with tag 0x" << std::hex << static_cast<uint32_t>(tag);
417 UNREACHABLE();
418 }
419 }
420
421 } // namespace ark::abc2program
422