1 /*
2 * Copyright (c) 2021-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 "disasm_backed_debug_info_extractor.h"
17
18 namespace ark::disasm {
DisasmBackedDebugInfoExtractor(const panda_file::File & file,std::function<void (panda_file::File::EntityId,std::string_view)> && onDisasmSourceName)19 DisasmBackedDebugInfoExtractor::DisasmBackedDebugInfoExtractor(
20 const panda_file::File &file,
21 std::function<void(panda_file::File::EntityId, std::string_view)> &&onDisasmSourceName)
22 : panda_file::DebugInfoExtractor(&file),
23 sourceNamePrefix_("disasm://" + file.GetFilename() + ":"),
24 onDisasmSourceName_(std::move(onDisasmSourceName))
25 {
26 disassembler_.SetFile(file);
27 }
28
GetLineNumberTable(panda_file::File::EntityId methodId) const29 const panda_file::LineNumberTable &DisasmBackedDebugInfoExtractor::GetLineNumberTable(
30 panda_file::File::EntityId methodId) const
31 {
32 if (GetDisassemblySourceName(methodId)) {
33 return GetDisassembly(methodId).lineTable;
34 }
35
36 return DebugInfoExtractor::GetLineNumberTable(methodId);
37 }
38
GetColumnNumberTable(panda_file::File::EntityId) const39 const panda_file::ColumnNumberTable &DisasmBackedDebugInfoExtractor::GetColumnNumberTable(
40 panda_file::File::EntityId /* method_id */) const
41 {
42 static panda_file::ColumnNumberTable empty;
43 return empty;
44 }
45
GetLocalVariableTable(panda_file::File::EntityId methodId) const46 const panda_file::LocalVariableTable &DisasmBackedDebugInfoExtractor::GetLocalVariableTable(
47 panda_file::File::EntityId methodId) const
48 {
49 if (GetDisassemblySourceName(methodId)) {
50 return GetDisassembly(methodId).localVariableTable;
51 }
52
53 return DebugInfoExtractor::GetLocalVariableTable(methodId);
54 }
55
GetParameterInfo(panda_file::File::EntityId methodId) const56 const std::vector<panda_file::DebugInfoExtractor::ParamInfo> &DisasmBackedDebugInfoExtractor::GetParameterInfo(
57 panda_file::File::EntityId methodId) const
58 {
59 if (GetDisassemblySourceName(methodId)) {
60 return GetDisassembly(methodId).parameterInfo;
61 }
62
63 return DebugInfoExtractor::GetParameterInfo(methodId);
64 }
65
GetSourceFile(panda_file::File::EntityId methodId) const66 const char *DisasmBackedDebugInfoExtractor::GetSourceFile(panda_file::File::EntityId methodId) const
67 {
68 if (auto &disassemblySourceName = GetDisassemblySourceName(methodId)) {
69 return disassemblySourceName->c_str();
70 }
71
72 return DebugInfoExtractor::GetSourceFile(methodId);
73 }
74
GetSourceCode(panda_file::File::EntityId methodId) const75 const char *DisasmBackedDebugInfoExtractor::GetSourceCode(panda_file::File::EntityId methodId) const
76 {
77 if (GetDisassemblySourceName(methodId)) {
78 return GetDisassembly(methodId).sourceCode.c_str();
79 }
80
81 return DebugInfoExtractor::GetSourceCode(methodId);
82 }
83
GetDisassemblySourceName(panda_file::File::EntityId methodId) const84 const std::optional<std::string> &DisasmBackedDebugInfoExtractor::GetDisassemblySourceName(
85 panda_file::File::EntityId methodId) const
86 {
87 os::memory::LockHolder lock(mutex_);
88
89 auto it = sourceNames_.find(methodId);
90 if (it != sourceNames_.end()) {
91 return it->second;
92 }
93
94 auto sourceFile = std::string(DebugInfoExtractor::GetSourceFile(methodId));
95 #if defined(PANDA_TARGET_OHOS) || defined(PANDA_TARGET_MOBILE)
96 if (!sourceFile.empty()) {
97 #else
98 if (os::file::File::IsRegularFile(sourceFile)) {
99 #endif
100 return sourceNames_.emplace(methodId, std::nullopt).first->second;
101 }
102
103 std::ostringstream name;
104 name << sourceNamePrefix_ << methodId;
105 auto &sourceName = sourceNames_.emplace(methodId, name.str()).first->second;
106
107 onDisasmSourceName_(methodId, *sourceName);
108
109 return sourceName;
110 }
111
112 const DisasmBackedDebugInfoExtractor::Disassembly &DisasmBackedDebugInfoExtractor::GetDisassembly(
113 panda_file::File::EntityId methodId) const
114 {
115 os::memory::LockHolder lock(mutex_);
116
117 auto it = disassemblies_.find(methodId);
118 if (it != disassemblies_.end()) {
119 return it->second;
120 }
121
122 pandasm::Function method("", SourceLanguage::PANDA_ASSEMBLY);
123 disassembler_.GetMethod(&method, methodId);
124
125 std::ostringstream sourceCode;
126 panda_file::LineNumberTable lineTable;
127 disassembler_.Serialize(method, sourceCode, true, &lineTable);
128
129 auto paramsNum = method.GetParamsNum();
130 std::vector<ParamInfo> parameterInfo(paramsNum);
131 for (auto argumentNum = 0U; argumentNum < paramsNum; ++argumentNum) {
132 parameterInfo[argumentNum].name = "a" + std::to_string(argumentNum);
133 parameterInfo[argumentNum].signature = method.params[argumentNum].type.GetDescriptor();
134 }
135
136 // We use -1 here as a number for Accumulator, because there is no other way
137 // to specify Accumulator as a register for local variable
138 auto totalRegNum = method.GetTotalRegs();
139 panda_file::LocalVariableTable localVariableTable(totalRegNum + 1, panda_file::LocalVariableInfo {});
140 for (auto vregNum = -1; vregNum < static_cast<int32_t>(totalRegNum); ++vregNum) {
141 localVariableTable[vregNum + 1].regNumber = vregNum;
142 localVariableTable[vregNum + 1].name = vregNum == -1 ? "acc" : "v" + std::to_string(vregNum);
143 localVariableTable[vregNum + 1].startOffset = 0;
144 localVariableTable[vregNum + 1].endOffset = UINT32_MAX;
145 }
146
147 return disassemblies_
148 .emplace(methodId, Disassembly {sourceCode.str(), std::move(lineTable), std::move(parameterInfo),
149 std::move(localVariableTable)})
150 .first->second;
151 }
152 } // namespace ark::disasm
153