14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include <mutex> 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_ci#include "ecmascript/common.h" 224514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_pt_location.h" 234514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile.h" 244514f5e3Sopenharmony_ci#include "ecmascript/mem/c_containers.h" 254514f5e3Sopenharmony_ci#include "ecmascript/mem/c_string.h" 264514f5e3Sopenharmony_ci 274514f5e3Sopenharmony_ci#include "libpandafile/class_data_accessor-inl.h" 284514f5e3Sopenharmony_ci#include "libpandafile/file.h" 294514f5e3Sopenharmony_ci#include "libpandabase/utils/utf.h" 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_cinamespace panda::ecmascript { 324514f5e3Sopenharmony_ciclass JSPandaFile; 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_cistruct LineTableEntry { 354514f5e3Sopenharmony_ci uint32_t offset; 364514f5e3Sopenharmony_ci int32_t line; 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_ci bool operator<(const LineTableEntry &other) const 394514f5e3Sopenharmony_ci { 404514f5e3Sopenharmony_ci return offset < other.offset; 414514f5e3Sopenharmony_ci } 424514f5e3Sopenharmony_ci}; 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_cistruct ColumnTableEntry { 454514f5e3Sopenharmony_ci uint32_t offset; 464514f5e3Sopenharmony_ci int32_t column; 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci bool operator<(const ColumnTableEntry &other) const 494514f5e3Sopenharmony_ci { 504514f5e3Sopenharmony_ci return offset < other.offset; 514514f5e3Sopenharmony_ci } 524514f5e3Sopenharmony_ci}; 534514f5e3Sopenharmony_ci 544514f5e3Sopenharmony_ciusing LineNumberTable = CVector<LineTableEntry>; 554514f5e3Sopenharmony_ciusing ColumnNumberTable = CVector<ColumnTableEntry>; 564514f5e3Sopenharmony_ciusing JSPtLocation = tooling::JSPtLocation; 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_ci/* 594514f5e3Sopenharmony_ci * Full version of LocalVariableInfo is defined in frontend, 604514f5e3Sopenharmony_ci * here only using name, reg_number, start_offset, and end_offset: 614514f5e3Sopenharmony_ci * std::string name 624514f5e3Sopenharmony_ci * std::string type 634514f5e3Sopenharmony_ci * std::string typeSignature 644514f5e3Sopenharmony_ci * int32_t regNumber 654514f5e3Sopenharmony_ci * uint32_t startOffset 664514f5e3Sopenharmony_ci * uint32_t endOffset 674514f5e3Sopenharmony_ci */ 684514f5e3Sopenharmony_cistruct LocalVariableInfo { 694514f5e3Sopenharmony_ci std::string name; 704514f5e3Sopenharmony_ci int32_t regNumber; 714514f5e3Sopenharmony_ci uint32_t startOffset; 724514f5e3Sopenharmony_ci uint32_t endOffset; 734514f5e3Sopenharmony_ci}; 744514f5e3Sopenharmony_ciusing LocalVariableTable = CVector<LocalVariableInfo>; 754514f5e3Sopenharmony_ci 764514f5e3Sopenharmony_ci// public for debugger 774514f5e3Sopenharmony_ciclass PUBLIC_API DebugInfoExtractor { 784514f5e3Sopenharmony_cipublic: 794514f5e3Sopenharmony_ci explicit DebugInfoExtractor(const JSPandaFile *jsPandaFile) : jsPandaFile_(jsPandaFile) 804514f5e3Sopenharmony_ci {} 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_ci ~DebugInfoExtractor() = default; 834514f5e3Sopenharmony_ci 844514f5e3Sopenharmony_ci const LineNumberTable &GetLineNumberTable(const panda_file::File::EntityId methodId); 854514f5e3Sopenharmony_ci 864514f5e3Sopenharmony_ci const ColumnNumberTable &GetColumnNumberTable(const panda_file::File::EntityId methodId); 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci const LocalVariableTable &GetLocalVariableTable(const panda_file::File::EntityId methodId); 894514f5e3Sopenharmony_ci 904514f5e3Sopenharmony_ci const std::string &GetSourceFile(const panda_file::File::EntityId methodId); 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_ci const std::string &GetSourceCode(const panda_file::File::EntityId methodId); 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ci template<class Callback> 954514f5e3Sopenharmony_ci bool MatchWithLocation(const Callback &cb, int32_t line, int32_t column, 964514f5e3Sopenharmony_ci const std::string &url, const std::unordered_set<std::string> &debugRecordName) 974514f5e3Sopenharmony_ci { 984514f5e3Sopenharmony_ci if (line == SPECIAL_LINE_MARK) { 994514f5e3Sopenharmony_ci return false; 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci auto &pandaFile = *jsPandaFile_->GetPandaFile(); 1024514f5e3Sopenharmony_ci auto classes = jsPandaFile_->GetClasses(); 1034514f5e3Sopenharmony_ci for (size_t i = 0; i < classes.Size(); i++) { 1044514f5e3Sopenharmony_ci panda_file::File::EntityId id(classes[i]); 1054514f5e3Sopenharmony_ci if (jsPandaFile_->IsExternal(id)) { 1064514f5e3Sopenharmony_ci continue; 1074514f5e3Sopenharmony_ci } 1084514f5e3Sopenharmony_ci 1094514f5e3Sopenharmony_ci CVector<panda_file::File::EntityId> methodIds; 1104514f5e3Sopenharmony_ci panda_file::ClassDataAccessor cda(pandaFile, id); 1114514f5e3Sopenharmony_ci CString recordName = JSPandaFile::ParseEntryPoint(utf::Mutf8AsCString(cda.GetDescriptor())); 1124514f5e3Sopenharmony_ci // Check record name in stage mode 1134514f5e3Sopenharmony_ci if (!jsPandaFile_->IsBundlePack()) { 1144514f5e3Sopenharmony_ci // the recordName for testcases is empty 1154514f5e3Sopenharmony_ci if (!debugRecordName.empty()) { 1164514f5e3Sopenharmony_ci auto iter = debugRecordName.find(std::string(recordName.c_str())); 1174514f5e3Sopenharmony_ci if (iter == debugRecordName.end()) { 1184514f5e3Sopenharmony_ci continue; 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci } 1214514f5e3Sopenharmony_ci } 1224514f5e3Sopenharmony_ci cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { 1234514f5e3Sopenharmony_ci methodIds.push_back(mda.GetMethodId()); 1244514f5e3Sopenharmony_ci }); 1254514f5e3Sopenharmony_ci 1264514f5e3Sopenharmony_ci int32_t minColumn = INT32_MAX; 1274514f5e3Sopenharmony_ci uint32_t currentOffset = UINT32_MAX; 1284514f5e3Sopenharmony_ci uint32_t minColumnOffset = UINT32_MAX; 1294514f5e3Sopenharmony_ci EntityId currentMethodId; 1304514f5e3Sopenharmony_ci EntityId minColumnMethodId; 1314514f5e3Sopenharmony_ci for (auto &methodId : methodIds) { 1324514f5e3Sopenharmony_ci const std::string &sourceFile = GetSourceFile(methodId); 1334514f5e3Sopenharmony_ci // the url for testcases is empty 1344514f5e3Sopenharmony_ci if (!url.empty() && sourceFile != url) { 1354514f5e3Sopenharmony_ci continue; 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci const LineNumberTable &lineTable = GetLineNumberTable(methodId); 1384514f5e3Sopenharmony_ci const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId); 1394514f5e3Sopenharmony_ci for (uint32_t j = 0; j < lineTable.size(); j++) { 1404514f5e3Sopenharmony_ci if (lineTable[j].line != line) { 1414514f5e3Sopenharmony_ci continue; 1424514f5e3Sopenharmony_ci } 1434514f5e3Sopenharmony_ci currentMethodId = methodId; 1444514f5e3Sopenharmony_ci currentOffset = lineTable[j].offset; 1454514f5e3Sopenharmony_ci uint32_t nextOffset = ((j == lineTable.size() - 1) ? UINT32_MAX : lineTable[j + 1].offset); 1464514f5e3Sopenharmony_ci for (const auto &pair : columnTable) { 1474514f5e3Sopenharmony_ci if (pair.offset >= currentOffset && pair.offset < nextOffset) { 1484514f5e3Sopenharmony_ci if (pair.column == column) { 1494514f5e3Sopenharmony_ci return cb(JSPtLocation(jsPandaFile_, methodId, pair.offset, url)); 1504514f5e3Sopenharmony_ci } else if (pair.column < minColumn && currentOffset < minColumnOffset) { 1514514f5e3Sopenharmony_ci minColumn = pair.column; 1524514f5e3Sopenharmony_ci minColumnOffset = currentOffset; 1534514f5e3Sopenharmony_ci minColumnMethodId = currentMethodId; 1544514f5e3Sopenharmony_ci } 1554514f5e3Sopenharmony_ci } 1564514f5e3Sopenharmony_ci } 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci } 1594514f5e3Sopenharmony_ci if (minColumn != INT32_MAX) { // find the smallest column for the corresponding row 1604514f5e3Sopenharmony_ci return cb(JSPtLocation(jsPandaFile_, minColumnMethodId, minColumnOffset, url)); 1614514f5e3Sopenharmony_ci } 1624514f5e3Sopenharmony_ci if (currentOffset != UINT32_MAX) { // find corresponding row, but not find corresponding column 1634514f5e3Sopenharmony_ci return cb(JSPtLocation(jsPandaFile_, currentMethodId, currentOffset, url)); 1644514f5e3Sopenharmony_ci } 1654514f5e3Sopenharmony_ci } 1664514f5e3Sopenharmony_ci return false; 1674514f5e3Sopenharmony_ci } 1684514f5e3Sopenharmony_ci 1694514f5e3Sopenharmony_ci template<class Callback> 1704514f5e3Sopenharmony_ci bool MatchLineWithOffset(const Callback &cb, panda_file::File::EntityId methodId, uint32_t offset) 1714514f5e3Sopenharmony_ci { 1724514f5e3Sopenharmony_ci int32_t line = 0; 1734514f5e3Sopenharmony_ci const LineNumberTable &lineTable = GetLineNumberTable(methodId); 1744514f5e3Sopenharmony_ci auto iter = std::upper_bound(lineTable.begin(), lineTable.end(), LineTableEntry {offset, 0}); 1754514f5e3Sopenharmony_ci if (iter != lineTable.begin()) { 1764514f5e3Sopenharmony_ci line = (iter - 1)->line; 1774514f5e3Sopenharmony_ci } 1784514f5e3Sopenharmony_ci return cb(line); 1794514f5e3Sopenharmony_ci } 1804514f5e3Sopenharmony_ci 1814514f5e3Sopenharmony_ci template<class Callback> 1824514f5e3Sopenharmony_ci bool MatchColumnWithOffset(const Callback &cb, panda_file::File::EntityId methodId, uint32_t offset) 1834514f5e3Sopenharmony_ci { 1844514f5e3Sopenharmony_ci int32_t column = 0; 1854514f5e3Sopenharmony_ci const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId); 1864514f5e3Sopenharmony_ci auto iter = std::upper_bound(columnTable.begin(), columnTable.end(), ColumnTableEntry {offset, 0}); 1874514f5e3Sopenharmony_ci if (iter != columnTable.begin()) { 1884514f5e3Sopenharmony_ci column = (iter - 1)->column; 1894514f5e3Sopenharmony_ci } 1904514f5e3Sopenharmony_ci return cb(column); 1914514f5e3Sopenharmony_ci } 1924514f5e3Sopenharmony_ci 1934514f5e3Sopenharmony_ci int32_t GetFristLine(panda_file::File::EntityId methodId) 1944514f5e3Sopenharmony_ci { 1954514f5e3Sopenharmony_ci const LineNumberTable &lineTable = GetLineNumberTable(methodId); 1964514f5e3Sopenharmony_ci auto tableSize = lineTable.size(); 1974514f5e3Sopenharmony_ci if (tableSize == 0) { 1984514f5e3Sopenharmony_ci return 0; 1994514f5e3Sopenharmony_ci } 2004514f5e3Sopenharmony_ci if (tableSize == 1) { 2014514f5e3Sopenharmony_ci return lineTable[0].line + 1; 2024514f5e3Sopenharmony_ci } 2034514f5e3Sopenharmony_ci int firstLineIndex = ((lineTable[0].line == SPECIAL_LINE_MARK) ? 1 : 0); 2044514f5e3Sopenharmony_ci return lineTable[firstLineIndex].line + 1; 2054514f5e3Sopenharmony_ci } 2064514f5e3Sopenharmony_ci 2074514f5e3Sopenharmony_ci int32_t GetFristColumn(panda_file::File::EntityId methodId) 2084514f5e3Sopenharmony_ci { 2094514f5e3Sopenharmony_ci const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId); 2104514f5e3Sopenharmony_ci auto tableSize = columnTable.size(); 2114514f5e3Sopenharmony_ci if (tableSize == 0) { 2124514f5e3Sopenharmony_ci return 0; 2134514f5e3Sopenharmony_ci } 2144514f5e3Sopenharmony_ci if (tableSize == 1) { 2154514f5e3Sopenharmony_ci return columnTable[0].column + 1; 2164514f5e3Sopenharmony_ci } 2174514f5e3Sopenharmony_ci int firstColumnIndex = ((columnTable[0].column == SPECIAL_LINE_MARK) ? 1 : 0); 2184514f5e3Sopenharmony_ci return columnTable[firstColumnIndex].column + 1; 2194514f5e3Sopenharmony_ci } 2204514f5e3Sopenharmony_ci 2214514f5e3Sopenharmony_ci void Extract(); 2224514f5e3Sopenharmony_ci 2234514f5e3Sopenharmony_ci constexpr static int32_t SPECIAL_LINE_MARK = -1; 2244514f5e3Sopenharmony_ci 2254514f5e3Sopenharmony_ciprivate: 2264514f5e3Sopenharmony_ci bool ExtractorMethodDebugInfo(const panda_file::File::EntityId methodId); 2274514f5e3Sopenharmony_ci void ExtractorMethodDebugInfo(const panda_file::File &pandaFile, 2284514f5e3Sopenharmony_ci const std::optional<panda_file::File::EntityId> sourceFileId, 2294514f5e3Sopenharmony_ci const std::optional<panda_file::File::EntityId> debugInfoId, 2304514f5e3Sopenharmony_ci uint32_t offset); 2314514f5e3Sopenharmony_ci struct MethodDebugInfo { 2324514f5e3Sopenharmony_ci std::string sourceFile; 2334514f5e3Sopenharmony_ci std::string sourceCode; 2344514f5e3Sopenharmony_ci LineNumberTable lineNumberTable; 2354514f5e3Sopenharmony_ci ColumnNumberTable columnNumberTable; 2364514f5e3Sopenharmony_ci LocalVariableTable localVariableTable; 2374514f5e3Sopenharmony_ci }; 2384514f5e3Sopenharmony_ci 2394514f5e3Sopenharmony_ci std::recursive_mutex mutex_; 2404514f5e3Sopenharmony_ci CUnorderedMap<uint32_t, MethodDebugInfo> methods_; 2414514f5e3Sopenharmony_ci const JSPandaFile *jsPandaFile_ {nullptr}; 2424514f5e3Sopenharmony_ci}; 2434514f5e3Sopenharmony_ci} // namespace panda::ecmascript 2444514f5e3Sopenharmony_ci 2454514f5e3Sopenharmony_ci#endif // ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H 246