1/*
2 * Copyright (c) 2021-2022 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 "debuginfoDumper.h"
17
18#include <macros.h>
19
20#include <sstream>
21#include <string>
22
23namespace panda::es2panda::debuginfo {
24
25DebugInfoDumper::DebugInfoDumper(const pandasm::Program *prog) : prog_(prog) {}
26
27static const char *PutComma(bool comma)
28{
29    return comma ? "," : "";
30}
31
32template <typename T>
33void DebugInfoDumper::WrapArray(const char *name, const std::vector<T> &array, bool comma)
34{
35    ss_ << std::endl;
36    Indent();
37    ss_ << "\"" << name << "\": "
38        << "[";
39
40    if (array.empty()) {
41        ss_ << "]" << PutComma(comma);
42        return;
43    }
44
45    ss_ << "\n";
46    indent_++;
47    // dump VariableDebugInfo in reverse order to match ts2panda
48    // NOLINTNEXTLINE
49    if constexpr (std::is_same_v<T, pandasm::debuginfo::LocalVariable>) {
50        typename std::vector<T>::const_reverse_iterator elem;
51        for (elem = array.rbegin(); elem != array.rend(); ++elem) {
52            Indent();
53            WriteVariableInfo(*elem);
54            (std::next(elem) == array.rend()) ? ss_ << "" : ss_ << ",";
55            ss_ << "\n";
56        }
57        // NOLINTNEXTLINE
58    } else {
59        typename std::vector<T>::const_iterator elem;
60        for (elem = array.begin(); elem != array.end(); ++elem) {
61            Indent();
62            // NOLINTNEXTLINE
63            if constexpr (std::is_same_v<T, pandasm::Ins>) {
64                WriteIns(*elem);
65                // NOLINTNEXTLINE
66            } else if constexpr (std::is_same_v<T, pandasm::Function::Parameter>) {
67                ss_ << "\"" << (*elem).type.GetName() << "\"";
68                // NOLINTNEXTLINE
69            } else if constexpr (std::is_same_v<T, std::string>) {
70                ss_ << "\"" << *elem << "\"";
71                // NOLINTNEXTLINE
72            } else if constexpr (std::is_same_v<T, std::variant<int64_t, double>>) {
73                if (std::holds_alternative<int64_t>(*elem)) {
74                    ss_ << std::to_string(std::get<int64_t>(*elem));
75                } else {
76                    ss_ << std::to_string(std::get<double>(*elem));
77                }
78                // NOLINTNEXTLINE
79            } else {
80                ss_ << std::to_string(*elem);
81            }
82
83            (std::next(elem) == array.end()) ? ss_ << "" : ss_ << ",";
84            ss_ << "\n";
85        }
86    }
87
88    indent_--;
89    Indent();
90
91    ss_ << "]" << PutComma(comma);
92}
93
94void DebugInfoDumper::WriteIns(const pandasm::Ins &ins)
95{
96    ss_ << "{";
97    {
98        pandasm::Ins insCopy;
99        insCopy.opcode = ins.opcode;
100        insCopy.set_label = ins.set_label;
101        insCopy.label = ins.label;
102        WriteProperty("opcode", insCopy.ToString());
103    }
104    indent_++;
105    WrapArray("regs", ins.regs);
106    WrapArray("ids", ins.ids);
107    WrapArray("imms", ins.imms);
108    ss_ << std::endl;
109    Indent();
110    ss_ << "\"label\": "
111        << "\"" << ins.label << "\",";
112    WritePosInfo(ins.ins_debug);
113    indent_--;
114    Indent();
115    ss_ << "}";
116}
117
118void DebugInfoDumper::WriteMetaData(const std::vector<pandasm::AnnotationData> &metaData)
119{
120    for (const auto &it : metaData) {
121        for (const auto &elem : it.GetElements()) {
122            pandasm::ScalarValue *value = elem.GetValue()->GetAsScalar();
123            if (value->GetType() == pandasm::Value::Type::STRING) {
124                WriteProperty(elem.GetName().c_str(), value->GetValue<std::string>(), false);
125            } else if (value->GetType() == pandasm::Value::Type::U32) {
126                WriteProperty(elem.GetName().c_str(), value->GetValue<size_t>());
127            }
128        }
129    }
130}
131
132void DebugInfoDumper::WritePosInfo(const pandasm::debuginfo::Ins &posInfo)
133{
134    ss_ << std::endl;
135    Indent();
136    ss_ << "\"debug_pos_info\": {";
137    WriteProperty("boundLeft", posInfo.bound_left);
138    WriteProperty("boundRight", posInfo.bound_right);
139    WriteProperty("sourceLineNum", static_cast<int32_t>(posInfo.line_number));
140    WriteProperty("wholeLine", posInfo.whole_line, false);
141    Indent();
142    ss_ << "}" << std::endl;
143}
144
145void DebugInfoDumper::WriteVariableInfo(const pandasm::debuginfo::LocalVariable &localVariableDebug)
146{
147    ss_ << "{";
148    WriteProperty("name", localVariableDebug.name);
149    WriteProperty("signature", localVariableDebug.signature);
150    WriteProperty("signatureType", localVariableDebug.signature_type);
151    WriteProperty("reg", localVariableDebug.reg);
152    WriteProperty("start", static_cast<size_t>(localVariableDebug.start));
153    WriteProperty("length", static_cast<size_t>(localVariableDebug.length), false);
154    Indent();
155    ss_ << "}";
156}
157
158void DebugInfoDumper::Dump()
159{
160    ss_ << "{\n";
161    indent_++;
162    Indent();
163    ss_ << "\"functions\": [" << std::endl;
164
165    auto iter = prog_->function_table.begin();
166
167    for (; iter != prog_->function_table.end(); ++iter) {
168        indent_++;
169        Indent();
170        ss_ << "{";
171        WriteProperty("name", iter->first);
172        ss_ << std::endl;
173
174        indent_++;
175        Indent();
176        ss_ << "\"signature\": {";
177        WriteProperty("retType", iter->second.return_type.GetName());
178        indent_++;
179        WrapArray("params", iter->second.params, false);
180        indent_ -= 2U;
181        ss_ << std::endl;
182        Indent();
183        ss_ << "},";
184
185        WrapArray("ins", iter->second.ins);
186        WrapArray("variables", iter->second.local_variable_debug);
187        WriteProperty("sourceFile", iter->second.source_file);
188        WriteProperty("sourceCode", iter->second.source_code);
189        // icSize - parameterLength - funcName
190        WriteMetaData(iter->second.metadata->GetAnnotations());
191
192        indent_--;
193        Indent();
194        ss_ << "}";
195
196        if (std::next(iter) != prog_->function_table.end()) {
197            ss_ << ",";
198        }
199
200        ss_ << std::endl;
201    }
202
203    indent_--;
204    Indent();
205    ss_ << "]" << std::endl;
206    ss_ << "}";
207    ss_ << std::endl;
208    std::cout << ss_.str();
209}
210
211void DebugInfoDumper::WriteProperty(const char *key, const Value &value, bool comma)
212{
213    ss_ << std::endl;
214    indent_++;
215    Indent();
216    ss_ << "\"" << key << "\": ";
217    if (std::holds_alternative<std::string>(value)) {
218        ss_ << "\"" << std::get<std::string>(value) << "\"";
219    } else if (std::holds_alternative<size_t>(value)) {
220        ss_ << std::to_string(std::get<size_t>(value));
221    } else if (std::holds_alternative<int32_t>(value)) {
222        ss_ << std::to_string(std::get<int32_t>(value));
223    }
224
225    comma ? ss_ << "," : ss_ << std::endl;
226    indent_--;
227}
228
229void DebugInfoDumper::Indent()
230{
231    for (int32_t i = 0; i <= indent_; i++) {
232        ss_ << "  ";
233    }
234}
235
236}  // namespace panda::es2panda::debuginfo
237