1 /*
2 * Copyright (c) 2021-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 "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 std::string_view sourceFile = DebugInfoExtractor::GetSourceFile(methodId);
95 if (!sourceFile.empty()) {
96 // Mark the queried method to be ignored, because debug information is available for it
97 return sourceNames_.emplace(methodId, std::nullopt).first->second;
98 }
99
100 std::ostringstream name;
101 name << sourceNamePrefix_ << methodId;
102 auto &sourceName = sourceNames_.emplace(methodId, name.str()).first->second;
103
104 onDisasmSourceName_(methodId, *sourceName);
105
106 return sourceName;
107 }
108
GetDisassembly(panda_file::File::EntityId methodId) const109 const DisasmBackedDebugInfoExtractor::Disassembly &DisasmBackedDebugInfoExtractor::GetDisassembly(
110 panda_file::File::EntityId methodId) const
111 {
112 os::memory::LockHolder lock(mutex_);
113
114 auto it = disassemblies_.find(methodId);
115 if (it != disassemblies_.end()) {
116 return it->second;
117 }
118
119 pandasm::Function method("", SourceLanguage::PANDA_ASSEMBLY);
120 disassembler_.GetMethod(&method, methodId);
121
122 std::ostringstream sourceCode;
123 panda_file::LineNumberTable lineTable;
124 disassembler_.Serialize(method, sourceCode, true, &lineTable);
125
126 auto paramsNum = method.GetParamsNum();
127 std::vector<ParamInfo> parameterInfo(paramsNum);
128 for (auto argumentNum = 0U; argumentNum < paramsNum; ++argumentNum) {
129 parameterInfo[argumentNum].name = "a" + std::to_string(argumentNum);
130 parameterInfo[argumentNum].signature = method.params[argumentNum].type.GetDescriptor();
131 }
132
133 // We use -1 here as a number for Accumulator, because there is no other way
134 // to specify Accumulator as a register for local variable
135 auto totalRegNum = method.GetTotalRegs();
136 panda_file::LocalVariableTable localVariableTable(totalRegNum + 1, panda_file::LocalVariableInfo {});
137 for (auto vregNum = -1; vregNum < static_cast<int32_t>(totalRegNum); ++vregNum) {
138 localVariableTable[vregNum + 1].regNumber = vregNum;
139 localVariableTable[vregNum + 1].name = vregNum == -1 ? "acc" : "v" + std::to_string(vregNum);
140 localVariableTable[vregNum + 1].startOffset = 0;
141 localVariableTable[vregNum + 1].endOffset = UINT32_MAX;
142 }
143
144 return disassemblies_
145 .emplace(methodId, Disassembly {sourceCode.str(), std::move(lineTable), std::move(parameterInfo),
146 std::move(localVariableTable)})
147 .first->second;
148 }
149
IsUserFile() const150 bool DisasmBackedDebugInfoExtractor::IsUserFile() const
151 {
152 return isUserFile_;
153 }
154
SetUserFile(bool isUser)155 void DisasmBackedDebugInfoExtractor::SetUserFile(bool isUser)
156 {
157 isUserFile_ = isUser;
158 }
159
160 } // namespace ark::disasm
161