• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "evaluate/debugInfoStorage.h"
17 #include "assembler/assembly-type.h"
18 #include "generated/signatures.h"
19 #include "evaluate/helpers.h"
20 
21 #include "libpandafile/class_data_accessor-inl.h"
22 #include "libpandafile/file-inl.h"
23 
24 namespace ark::es2panda::evaluate {
25 
26 namespace {
27 
GetFullRecordName(const panda_file::File & pf,const panda_file::File::EntityId & classId)28 std::string GetFullRecordName(const panda_file::File &pf, const panda_file::File::EntityId &classId)
29 {
30     std::string name = utf::Mutf8AsCString(pf.GetStringData(classId).data);
31 
32     auto type = pandasm::Type::FromDescriptor(name);
33     type = pandasm::Type(type.GetComponentName(), type.GetRank());
34 
35     return type.GetPandasmName();
36 }
37 
38 }  // namespace
39 
ImportExportTable(ArenaAllocator * allocator)40 ImportExportTable::ImportExportTable(ArenaAllocator *allocator)
41     : imports_(allocator->Adapter()), exports_(allocator->Adapter())
42 {
43 }
44 
DebugInfoStorage(const util::Options & options,ArenaAllocator * allocator)45 DebugInfoStorage::DebugInfoStorage(const util::Options &options, ArenaAllocator *allocator)
46     : allocator_(allocator), sourceFileToDebugInfo_(allocator->Adapter()), moduleNameToDebugInfo_(allocator->Adapter())
47 {
48     for (const auto &pfPath : options.GetDebuggerEvalPandaFiles()) {
49         LoadFileDebugInfo(pfPath);
50     }
51 }
52 
LoadFileDebugInfo(std::string_view pfPath)53 void DebugInfoStorage::LoadFileDebugInfo(std::string_view pfPath)
54 {
55     auto pf = panda_file::OpenPandaFile(pfPath);
56     if (!pf) {
57         LOG(FATAL, ES2PANDA) << "Failed to load a provided abc file: " << pfPath;
58     }
59 
60     for (auto id : pf->GetClasses()) {
61         panda_file::File::EntityId classId(id);
62         if (pf->IsExternal(classId)) {
63             continue;
64         }
65 
66         panda_file::ClassDataAccessor cda(*pf, classId);
67         bool isModule = false;
68         cda.EnumerateAnnotation(ANNOTATION_MODULE.data(), [&isModule](auto &) { return (isModule = true); });
69         if (!isModule) {
70             continue;
71         }
72         auto recordName = GetFullRecordName(*pf, classId);
73 
74         std::string_view moduleName = helpers::SplitRecordName(recordName).first;
75         auto *debugInfo = allocator_->New<FileDebugInfo>(std::move(pf), classId, moduleName);
76         auto sourceFileId = debugInfo->globalClassAcc.GetSourceFileId();
77         ES2PANDA_ASSERT(sourceFileId.has_value());
78         std::string_view sourceFileName = utf::Mutf8AsCString(debugInfo->pf->GetStringData(*sourceFileId).data);
79         debugInfo->sourceFilePath = sourceFileName;
80 
81         sourceFileToDebugInfo_.emplace(sourceFileName, debugInfo);
82         moduleNameToDebugInfo_.emplace(moduleName, debugInfo);
83         return;
84     }
85 
86     LOG(FATAL, ES2PANDA) << "ETSGLOBAL not found in provided file: " << pfPath;
87 }
88 
GetPandaFile(std::string_view filePath)89 const panda_file::File *DebugInfoStorage::GetPandaFile(std::string_view filePath)
90 {
91     auto iter = sourceFileToDebugInfo_.find(filePath);
92     if (iter == sourceFileToDebugInfo_.end()) {
93         return nullptr;
94     }
95     return iter->second->pf.get();
96 }
97 
GetImportExportTable(std::string_view filePath)98 const ImportExportTable *DebugInfoStorage::GetImportExportTable(std::string_view filePath)
99 {
100     auto iter = sourceFileToDebugInfo_.find(filePath);
101     if (iter == sourceFileToDebugInfo_.end()) {
102         return nullptr;
103     }
104     return &LazyLoadImportExportTable(iter->second);
105 }
106 
GetGlobalClassAccessor(std::string_view filePath)107 panda_file::ClassDataAccessor *DebugInfoStorage::GetGlobalClassAccessor(std::string_view filePath)
108 {
109     auto iter = sourceFileToDebugInfo_.find(filePath);
110     if (iter == sourceFileToDebugInfo_.end()) {
111         return nullptr;
112     }
113     return &iter->second->globalClassAcc;
114 }
115 
GetModuleName(std::string_view filePath)116 std::string_view DebugInfoStorage::GetModuleName(std::string_view filePath)
117 {
118     auto iter = sourceFileToDebugInfo_.find(filePath);
119     if (iter == sourceFileToDebugInfo_.end()) {
120         return {};
121     }
122     return iter->second->moduleName;
123 }
124 
FindClass(std::string_view filePath,std::string_view className)125 panda_file::File::EntityId DebugInfoStorage::FindClass(std::string_view filePath, std::string_view className)
126 {
127     auto iter = sourceFileToDebugInfo_.find(filePath);
128     if (iter == sourceFileToDebugInfo_.end()) {
129         return panda_file::File::EntityId();
130     }
131 
132     const auto &records = LazyLoadRecords(iter->second);
133 
134     auto classIter = records.find(className);
135     return classIter == records.end() ? panda_file::File::EntityId() : classIter->second;
136 }
137 
FillEvaluateContext(EvaluateContext & context)138 bool DebugInfoStorage::FillEvaluateContext(EvaluateContext &context)
139 {
140     const auto *contextPandaFile = GetPandaFile(context.sourceFilePath.Utf8());
141     if (contextPandaFile == nullptr) {
142         LOG(WARNING, ES2PANDA) << "Could not find context file: " << context.sourceFilePath << std::endl;
143         return false;
144     }
145 
146     context.file = contextPandaFile;
147     context.extractor = std::make_unique<panda_file::DebugInfoExtractor>(contextPandaFile);
148 
149     for (auto methodId : context.extractor->GetMethodIdList()) {
150         for (const auto &entry : context.extractor->GetLineNumberTable(methodId)) {
151             if (context.lineNumber == entry.line) {
152                 context.methodId = methodId;
153                 context.bytecodeOffset = entry.offset;
154                 util::UString sourceFilePath(std::string_view(context.extractor->GetSourceFile(methodId)), allocator_);
155                 context.sourceFilePath = sourceFilePath.View();
156                 return true;
157             }
158         }
159     }
160     LOG(WARNING, ES2PANDA) << "Could not find code at line: " << context.lineNumber << std::endl;
161     return false;
162 }
163 
LazyLoadImportExportTable(FileDebugInfo * info)164 const ImportExportTable &DebugInfoStorage::LazyLoadImportExportTable(FileDebugInfo *info)
165 {
166     ES2PANDA_ASSERT(info);
167 
168     if (info->importExportTable.has_value()) {
169         return *info->importExportTable;
170     }
171 
172     // NOTE: load table after it is implemented in compiler.
173     info->importExportTable.emplace(allocator_);
174     return info->importExportTable.value();
175 }
176 
LazyLoadRecords(FileDebugInfo * info)177 const FileDebugInfo::RecordsMap &DebugInfoStorage::LazyLoadRecords(FileDebugInfo *info)
178 {
179     ES2PANDA_ASSERT(info);
180 
181     if (info->records.has_value()) {
182         return *info->records;
183     }
184 
185     info->records.emplace(allocator_->Adapter());
186     auto &records = *info->records;
187 
188     const auto *pf = info->pf.get();
189     for (auto id : pf->GetClasses()) {
190         panda_file::File::EntityId classId(id);
191         if (pf->IsExternal(classId)) {
192             // Сlass that marked in currect .abc file as <external> should be define in some other .abc file.
193             // Thus we will not lose information about this class.
194             continue;
195         }
196 
197         std::string fullRecordName = GetFullRecordName(*pf, classId);
198         // Be aware of lifecycle of string and string_view
199         auto splitedPair = helpers::SplitRecordName(fullRecordName);
200         auto recordName = splitedPair.second;
201         auto recordNameView = util::UString(recordName, allocator_).View();
202         if (!records.emplace(recordNameView, classId).second) {
203             LOG(FATAL, ES2PANDA) << "Failed to emplace class '" << recordNameView << "' in records."
204                                  << "There should be only one declaration of the same class.";
205         }
206     }
207 
208     return records;
209 }
210 
GetDebugInfoByModuleName(std::string_view moduleName) const211 FileDebugInfo *DebugInfoStorage::GetDebugInfoByModuleName(std::string_view moduleName) const
212 {
213     auto find = moduleNameToDebugInfo_.find(moduleName);
214     if (find != moduleNameToDebugInfo_.end()) {
215         return find->second;
216     }
217     return nullptr;
218 }
219 
220 }  // namespace ark::es2panda::evaluate
221