1 /*
2 * Copyright (c) 2024-2025 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.functionStaticTable) {
192 DumpFunction(os, it.second);
193 }
194 for (const auto &it : program.functionInstanceTable) {
195 DumpFunction(os, it.second);
196 }
197 }
198
DumpFunction(std::ostream & os,const pandasm::Function & function) const199 void PandasmProgramDumper::DumpFunction(std::ostream &os, const pandasm::Function &function) const
200 {
201 os << DUMP_TITLE_FUNCTION;
202 os << function.returnType.GetPandasmName() << " " << function.name << "(";
203 if (!function.params.empty()) {
204 os << function.params[0].type.GetPandasmName() << " a0";
205
206 for (size_t i = 1; i < function.params.size(); i++) {
207 os << ", " << function.params[i].type.GetPandasmName() << " a" << (size_t)i;
208 }
209 }
210 os << ")";
211
212 const std::string signature = pandasm::GetFunctionSignatureFromName(function.name, function.params);
213
214 DumpMetaData(os, *function.metadata);
215
216 if (!function.HasImplementation()) {
217 os << DUMP_CONTENT_DOUBLE_ENDL;
218 return;
219 }
220
221 os << " {";
222
223 os << DUMP_CONTENT_SINGLE_ENDL;
224
225 DumpInstructions(os, function);
226
227 os << "}" << DUMP_CONTENT_DOUBLE_ENDL;
228 }
229
DumpInstructions(std::ostream & os,const pandasm::Function & function) const230 void PandasmProgramDumper::DumpInstructions(std::ostream &os, const pandasm::Function &function) const
231 {
232 for (const auto &instr : function.ins) {
233 std::string ins = instr.ToString("", function.GetParamsNum() != 0, function.regsNum);
234 if (instr.setLabel) {
235 std::string delim = ": ";
236 size_t pos = ins.find(delim);
237 std::string label = ins.substr(0, pos);
238 ins.erase(0, pos + delim.length());
239
240 os << label << ":";
241 os << DUMP_CONTENT_SINGLE_ENDL;
242 }
243
244 os << "\t";
245 os << ins;
246 os << DUMP_CONTENT_SINGLE_ENDL;
247 }
248 }
249
DumpStrings(std::ostream & os,const pandasm::Program & program) const250 void PandasmProgramDumper::DumpStrings(std::ostream &os, const pandasm::Program &program) const
251 {
252 if (HasNoAbcInput()) {
253 DumpStringsByProgram(os, program);
254 } else {
255 DumpStringsByStringTable(os, *stringTable_);
256 }
257 }
258
DumpStringsByStringTable(std::ostream & os,const AbcStringTable & stringTable) const259 void PandasmProgramDumper::DumpStringsByStringTable(std::ostream &os, const AbcStringTable &stringTable) const
260 {
261 os << DUMP_TITLE_SEPARATOR;
262 os << DUMP_TITLE_STRING;
263 stringTable.Dump(os);
264 os << DUMP_CONTENT_SINGLE_ENDL;
265 }
266
DumpStringsByProgram(std::ostream & os,const pandasm::Program & program) const267 void PandasmProgramDumper::DumpStringsByProgram(std::ostream &os, const pandasm::Program &program) const
268 {
269 os << DUMP_TITLE_SEPARATOR;
270 os << DUMP_TITLE_STRING;
271 os << DUMP_CONTENT_SINGLE_ENDL;
272 for (const std::string &str : program.strings) {
273 os << str << DUMP_CONTENT_SINGLE_ENDL;
274 }
275 os << DUMP_CONTENT_SINGLE_ENDL;
276 }
277
DumpLiteralArray(std::ostream & os,const pandasm::LiteralArray & litArray,const pandasm::Program & program) const278 void PandasmProgramDumper::DumpLiteralArray(std::ostream &os, const pandasm::LiteralArray &litArray,
279 const pandasm::Program &program) const
280 {
281 if (litArray.literals.empty()) {
282 return;
283 }
284
285 bool isConst = litArray.literals[0].IsArray();
286
287 std::stringstream specifiers {};
288 if (isConst) {
289 specifiers << LiteralTagToString(litArray.literals[0].tag, program) << " " << litArray.literals.size() << " ";
290 }
291 os << specifiers.str() << "{";
292
293 DumpValues(litArray, isConst, os, program);
294
295 os << "}" << DUMP_CONTENT_SINGLE_ENDL;
296 }
297
298 template <typename T>
LiteralIntegralValueToString(const pandasm::LiteralArray::Literal & lit)299 std::string LiteralIntegralValueToString(const pandasm::LiteralArray::Literal &lit)
300 {
301 std::stringstream res {};
302 T value = std::get<T>(lit.value);
303 if (lit.IsSigned()) {
304 res << +static_cast<typename std::make_signed<T>::type>(value);
305 } else {
306 res << +value;
307 }
308 return res.str();
309 }
310
LiteralValueToString(const pandasm::LiteralArray::Literal & lit) const311 std::string PandasmProgramDumper::LiteralValueToString(const pandasm::LiteralArray::Literal &lit) const
312 {
313 if (lit.IsBoolValue()) {
314 std::stringstream res {};
315 res << (std::get<bool>(lit.value));
316 return res.str();
317 }
318
319 if (lit.IsByteValue()) {
320 return LiteralIntegralValueToString<uint8_t>(lit);
321 }
322
323 if (lit.IsShortValue()) {
324 return LiteralIntegralValueToString<uint16_t>(lit);
325 }
326
327 if (lit.IsIntegerValue()) {
328 return LiteralIntegralValueToString<uint32_t>(lit);
329 }
330
331 if (lit.IsLongValue()) {
332 return LiteralIntegralValueToString<uint64_t>(lit);
333 }
334
335 if (lit.IsDoubleValue()) {
336 std::stringstream res {};
337 res << std::get<double>(lit.value);
338 return res.str();
339 }
340
341 if (lit.IsFloatValue()) {
342 std::stringstream res {};
343 res << std::get<float>(lit.value);
344 return res.str();
345 }
346
347 if (lit.IsStringValue()) {
348 std::stringstream res {};
349 res << "\"" << std::get<std::string>(lit.value) << "\"";
350 return res.str();
351 }
352
353 UNREACHABLE();
354 }
355
DumpValues(const pandasm::LiteralArray & litArray,const bool isConst,std::ostream & os,const pandasm::Program & program) const356 void PandasmProgramDumper::DumpValues(const pandasm::LiteralArray &litArray, const bool isConst, std::ostream &os,
357 const pandasm::Program &program) const
358 {
359 std::string separator = (isConst) ? (" ") : ("\n");
360
361 os << separator;
362
363 if (isConst) {
364 for (const auto &l : litArray.literals) {
365 os << LiteralValueToString(l) << separator;
366 }
367 } else {
368 for (const auto &l : litArray.literals) {
369 os << "\t" << LiteralTagToString(l.tag, program) << " " << LiteralValueToString(l) << separator;
370 }
371 }
372 }
373
LiteralTagToString(const panda_file::LiteralTag & tag,const pandasm::Program & program) const374 std::string PandasmProgramDumper::LiteralTagToString(const panda_file::LiteralTag &tag,
375 const pandasm::Program &program) const
376 {
377 switch (tag) {
378 case panda_file::LiteralTag::BOOL:
379 case panda_file::LiteralTag::ARRAY_U1:
380 return "u1";
381 case panda_file::LiteralTag::ARRAY_U8:
382 return "u8";
383 case panda_file::LiteralTag::ARRAY_I8:
384 return "i8";
385 case panda_file::LiteralTag::ARRAY_U16:
386 return "u16";
387 case panda_file::LiteralTag::ARRAY_I16:
388 return "i16";
389 case panda_file::LiteralTag::ARRAY_U32:
390 return "u32";
391 case panda_file::LiteralTag::INTEGER:
392 case panda_file::LiteralTag::ARRAY_I32:
393 return "i32";
394 case panda_file::LiteralTag::ARRAY_U64:
395 return "u64";
396 case panda_file::LiteralTag::BIGINT:
397 case panda_file::LiteralTag::ARRAY_I64:
398 return "i64";
399 case panda_file::LiteralTag::FLOAT:
400 case panda_file::LiteralTag::ARRAY_F32:
401 return "f32";
402 case panda_file::LiteralTag::DOUBLE:
403 case panda_file::LiteralTag::ARRAY_F64:
404 return "f64";
405 case panda_file::LiteralTag::STRING:
406 case panda_file::LiteralTag::ARRAY_STRING:
407 return pandasm::Type::FromDescriptor(panda_file::GetStringClassDescriptor(program.lang)).GetPandasmName();
408 case panda_file::LiteralTag::ACCESSOR:
409 return "accessor";
410 case panda_file::LiteralTag::NULLVALUE:
411 return "nullvalue";
412 case panda_file::LiteralTag::METHODAFFILIATE:
413 return "method_affiliate";
414 case panda_file::LiteralTag::METHOD:
415 return "method";
416 case panda_file::LiteralTag::GENERATORMETHOD:
417 return "generator_method";
418 default:
419 LOG(ERROR, ABC2PROGRAM) << "Unsupported literal with tag 0x" << std::hex << static_cast<uint32_t>(tag);
420 UNREACHABLE();
421 }
422 }
423
424 } // namespace ark::abc2program
425