• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #ifndef ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H
17 #define ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H
18 
19 #include "ecmascript/common.h"
20 #include "ecmascript/debugger/js_pt_location.h"
21 #include "ecmascript/jspandafile/js_pandafile.h"
22 #include "ecmascript/mem/c_containers.h"
23 #include "ecmascript/mem/c_string.h"
24 
25 #include "libpandafile/file.h"
26 
27 namespace panda::ecmascript {
28 class JSPandaFile;
29 
30 struct LineTableEntry {
31     uint32_t offset;
32     int32_t line;
33 
34     bool operator<(const LineTableEntry &other) const
35     {
36         return offset < other.offset;
37     }
38 };
39 
40 struct ColumnTableEntry {
41     uint32_t offset;
42     int32_t column;
43 
44     bool operator<(const ColumnTableEntry &other) const
45     {
46         return offset < other.offset;
47     }
48 };
49 
50 using LineNumberTable = CVector<LineTableEntry>;
51 using ColumnNumberTable = CVector<ColumnTableEntry>;
52 using JSPtLocation = tooling::JSPtLocation;
53 
54 /*
55  * LocalVariableInfo define in frontend, now only use name and regNumber:
56  *   std::string name
57  *   std::string type
58  *   std::string typeSignature
59  *   int32_t regNumber
60  *   uint32_t startOffset
61  *   uint32_t endOffset
62  */
63 using LocalVariableTable = CUnorderedMap<std::string, int32_t>;  // name, regNumber
64 
65 // public for debugger
66 class PUBLIC_API DebugInfoExtractor {
67 public:
68     explicit DebugInfoExtractor(const JSPandaFile *jsPandaFile);
69 
70     ~DebugInfoExtractor() = default;
71 
72     DEFAULT_COPY_SEMANTIC(DebugInfoExtractor);
73     DEFAULT_MOVE_SEMANTIC(DebugInfoExtractor);
74 
75     const LineNumberTable &GetLineNumberTable(panda_file::File::EntityId methodId) const;
76 
77     const ColumnNumberTable &GetColumnNumberTable(panda_file::File::EntityId methodId) const;
78 
79     const LocalVariableTable &GetLocalVariableTable(panda_file::File::EntityId methodId) const;
80 
81     const std::string &GetSourceFile(panda_file::File::EntityId methodId) const;
82 
83     const std::string &GetSourceCode(panda_file::File::EntityId methodId) const;
84 
85     CVector<panda_file::File::EntityId> GetMethodIdList() const;
86 
87     bool ContainsMethod(panda_file::File::EntityId methodId) const;
88 
89     template<class Callback>
MatchWithLocation(const Callback & cb,int32_t line,int32_t column,const std::string & url)90     bool MatchWithLocation(const Callback &cb, int32_t line, int32_t column, const std::string &url) const
91     {
92         if (line == SPECIAL_LINE_MARK) {
93             return false;
94         }
95 
96         for (const auto &[id, debugInfo] : methods_) {
97             // the url for testcases is empty
98             if (!url.empty() && url != debugInfo.sourceFile) {
99                 continue;
100             }
101             auto methodId = panda_file::File::EntityId(id);
102             const LineNumberTable &lineTable = GetLineNumberTable(methodId);
103             const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId);
104             for (uint32_t i = 0; i < lineTable.size(); i++) {
105                 if (lineTable[i].line != line) {
106                     continue;
107                 }
108                 uint32_t currentOffset = lineTable[i].offset;
109                 uint32_t nextOffset = ((i == lineTable.size() - 1) ? UINT32_MAX : lineTable[i + 1].offset);
110                 for (const auto &pair : columnTable) {
111                     if (pair.column == column && pair.offset >= currentOffset && pair.offset < nextOffset) {
112                         return cb(JSPtLocation(jsPandaFile_, methodId, pair.offset, url));
113                     }
114                 }
115                 return cb(JSPtLocation(jsPandaFile_, methodId, currentOffset, url));
116             }
117         }
118         return false;
119     }
120 
121     template<class Callback>
MatchLineWithOffset(const Callback & cb,panda_file::File::EntityId methodId,uint32_t offset)122     bool MatchLineWithOffset(const Callback &cb, panda_file::File::EntityId methodId, uint32_t offset)
123     {
124         int32_t line = 0;
125         const LineNumberTable &lineTable = GetLineNumberTable(methodId);
126         auto iter = std::upper_bound(lineTable.begin(), lineTable.end(), LineTableEntry {offset, 0});
127         if (iter != lineTable.begin()) {
128             line = (iter - 1)->line;
129         }
130         return cb(line);
131     }
132 
133     template<class Callback>
MatchColumnWithOffset(const Callback & cb,panda_file::File::EntityId methodId,uint32_t offset)134     bool MatchColumnWithOffset(const Callback &cb, panda_file::File::EntityId methodId, uint32_t offset)
135     {
136         int32_t column = 0;
137         const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId);
138         auto iter = std::upper_bound(columnTable.begin(), columnTable.end(), ColumnTableEntry {offset, 0});
139         if (iter != columnTable.begin()) {
140             column = (iter - 1)->column;
141         }
142         return cb(column);
143     }
144 
145 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
GetFristLine(panda_file::File::EntityId methodId)146     int32_t GetFristLine(panda_file::File::EntityId methodId)
147     {
148         const LineNumberTable &lineTable = GetLineNumberTable(methodId);
149         if (lineTable.size() <= 1) {
150             return 0;
151         }
152         return lineTable[1].line + 1;
153     }
154 
GetFristColumn(panda_file::File::EntityId methodId)155     int32_t GetFristColumn(panda_file::File::EntityId methodId)
156     {
157         const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId);
158         if (columnTable.size() == 0) {
159             return 0;
160         }
161         return columnTable[0].column + 1;
162     }
163 #endif
164 
165     constexpr static int32_t SPECIAL_LINE_MARK = -1;
166 
167 private:
168     void Extract();
169 
170     struct MethodDebugInfo {
171         std::string sourceFile;
172         std::string sourceCode;
173         LineNumberTable lineNumberTable;
174         ColumnNumberTable columnNumberTable;
175         LocalVariableTable localVariableTable;
176     };
177 
178     CUnorderedMap<uint32_t, MethodDebugInfo> methods_;
179     const JSPandaFile *jsPandaFile_ {nullptr};
180 };
181 }  // namespace panda::ecmascript
182 
183 #endif  // ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H
184