• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef LIBPANDAFILE_LINE_NUMBER_PROGRAM_H
17 #define LIBPANDAFILE_LINE_NUMBER_PROGRAM_H
18 
19 #include "file-inl.h"
20 #include "file_items.h"
21 
22 namespace ark::panda_file {
23 
24 class LineProgramState {
25 public:
LineProgramState(const File & pf,File::EntityId file,size_t line,Span<const uint8_t> constantPool)26     LineProgramState(const File &pf, File::EntityId file, size_t line, Span<const uint8_t> constantPool)
27         : pf_(pf), file_(file), line_(line), constantPool_(constantPool)
28     {
29     }
30 
AdvanceLine(int32_t v)31     void AdvanceLine(int32_t v)
32     {
33         line_ += static_cast<size_t>(v);
34     }
35 
AdvancePc(uint32_t v)36     void AdvancePc(uint32_t v)
37     {
38         address_ += v;
39     }
40 
SetFile(uint32_t offset)41     void SetFile(uint32_t offset)
42     {
43         file_ = File::EntityId(offset);
44     }
45 
GetFile()46     const uint8_t *GetFile() const
47     {
48         return pf_.GetStringData(file_).data;
49     }
50 
HasFile()51     bool HasFile() const
52     {
53         return file_.IsValid();
54     }
55 
SetSourceCode(uint32_t offset)56     void SetSourceCode(uint32_t offset)
57     {
58         sourceCode_ = File::EntityId(offset);
59     }
60 
GetSourceCode()61     const uint8_t *GetSourceCode() const
62     {
63         ASSERT(HasSourceCode());
64         return pf_.GetStringData(sourceCode_).data;
65     }
66 
HasSourceCode()67     bool HasSourceCode() const
68     {
69         return sourceCode_.IsValid();
70     }
71 
GetLine()72     size_t GetLine() const
73     {
74         return line_;
75     }
76 
SetColumn(int32_t c)77     void SetColumn(int32_t c)
78     {
79         column_ = static_cast<size_t>(c);
80     }
81 
GetColumn()82     size_t GetColumn() const
83     {
84         return column_;
85     }
86 
GetAddress()87     uint32_t GetAddress() const
88     {
89         return address_;
90     }
91 
ReadULeb128()92     uint32_t ReadULeb128()
93     {
94         return panda_file::helpers::ReadULeb128(&constantPool_);
95     }
96 
ReadSLeb128()97     int32_t ReadSLeb128()
98     {
99         return panda_file::helpers::ReadLeb128(&constantPool_);
100     }
101 
GetPandaFile()102     const File &GetPandaFile() const
103     {
104         return pf_;
105     }
106 
107 private:
108     const File &pf_;
109 
110     File::EntityId file_;
111     File::EntityId sourceCode_;
112     size_t line_;
113     size_t column_ {0};
114     Span<const uint8_t> constantPool_;
115 
116     uint32_t address_ {0};
117 };
118 
119 template <class Handler>
120 class LineNumberProgramProcessor {
121 public:
LineNumberProgramProcessor(const uint8_t * program,Handler * handler)122     LineNumberProgramProcessor(const uint8_t *program, Handler *handler)
123         : state_(handler->GetState()), program_(program), handler_(handler)
124     {
125     }
126 
127     ~LineNumberProgramProcessor() = default;
128 
129     NO_COPY_SEMANTIC(LineNumberProgramProcessor);
130     NO_MOVE_SEMANTIC(LineNumberProgramProcessor);
131 
132     // CC-OFFNXT(G.FUN.01-CPP, huge_method[C]) big switch case
Process()133     void Process()
134     {
135         handler_->ProcessBegin();
136 
137         auto opcode = ReadOpcode();
138         bool res = false;
139         while (opcode != Opcode::END_SEQUENCE) {
140             switch (opcode) {
141                 case Opcode::ADVANCE_LINE: {
142                     res = HandleAdvanceLine();
143                     break;
144                 }
145                 case Opcode::ADVANCE_PC: {
146                     res = HandleAdvancePc();
147                     break;
148                 }
149                 case Opcode::SET_FILE: {
150                     res = HandleSetFile();
151                     break;
152                 }
153                 case Opcode::SET_SOURCE_CODE: {
154                     res = HandleSetSourceCode();
155                     break;
156                 }
157                 case Opcode::SET_PROLOGUE_END: {
158                     res = HandleSetPrologueEnd();
159                     break;
160                 }
161                 case Opcode::SET_EPILOGUE_BEGIN: {
162                     res = HandleSetEpilogueBegin();
163                     break;
164                 }
165                 case Opcode::START_LOCAL: {
166                     res = HandleStartLocal();
167                     break;
168                 }
169                 case Opcode::START_LOCAL_EXTENDED: {
170                     res = HandleStartLocalExtended();
171                     break;
172                 }
173                 case Opcode::RESTART_LOCAL: {
174                     res = HandleRestartLocal();
175                     break;
176                 }
177                 case Opcode::END_LOCAL: {
178                     res = HandleEndLocal();
179                     break;
180                 }
181                 case Opcode::SET_COLUMN: {
182                     res = HandleSetColumn();
183                     break;
184                 }
185                 default: {
186                     res = HandleSpecialOpcode(opcode);
187                     break;
188                 }
189             }
190 
191             if (!res) {
192                 break;
193             }
194 
195             opcode = ReadOpcode();
196         }
197 
198         handler_->ProcessEnd();
199     }
200 
201 private:
202     using Opcode = LineNumberProgramItem::Opcode;
203 
ReadOpcode()204     Opcode ReadOpcode()
205     {
206         auto opcode = static_cast<Opcode>(*program_);
207         ++program_;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
208         return opcode;
209     }
210 
ReadRegisterNumber()211     int32_t ReadRegisterNumber()
212     {
213         auto [regiserNumber, n, isFull] = leb128::DecodeSigned<int32_t>(program_);
214         LOG_IF(!isFull, FATAL, COMMON) << "Cannot read a register number";
215         program_ += n;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
216         return regiserNumber;
217     }
218 
HandleAdvanceLine()219     bool HandleAdvanceLine() const
220     {
221         auto lineDiff = state_->ReadSLeb128();
222         return handler_->HandleAdvanceLine(lineDiff);
223     }
224 
HandleAdvancePc()225     bool HandleAdvancePc() const
226     {
227         auto pcDiff = state_->ReadULeb128();
228         return handler_->HandleAdvancePc(pcDiff);
229     }
230 
HandleSetFile()231     bool HandleSetFile() const
232     {
233         return handler_->HandleSetFile(state_->ReadULeb128());
234     }
235 
HandleSetSourceCode()236     bool HandleSetSourceCode() const
237     {
238         return handler_->HandleSetSourceCode(state_->ReadULeb128());
239     }
240 
HandleSetPrologueEnd()241     bool HandleSetPrologueEnd() const
242     {
243         return handler_->HandleSetPrologueEnd();
244     }
245 
HandleSetEpilogueBegin()246     bool HandleSetEpilogueBegin() const
247     {
248         return handler_->HandleSetEpilogueBegin();
249     }
250 
HandleStartLocal()251     bool HandleStartLocal()
252     {
253         auto regNumber = ReadRegisterNumber();
254         auto nameIndex = state_->ReadULeb128();
255         auto typeIndex = state_->ReadULeb128();
256         return handler_->HandleStartLocal(regNumber, nameIndex, typeIndex);
257     }
258 
HandleStartLocalExtended()259     bool HandleStartLocalExtended()
260     {
261         auto regNumber = ReadRegisterNumber();
262         auto nameIndex = state_->ReadULeb128();
263         auto typeIndex = state_->ReadULeb128();
264         auto typeSignatureIndex = state_->ReadULeb128();
265         return handler_->HandleStartLocalExtended(regNumber, nameIndex, typeIndex, typeSignatureIndex);
266     }
267 
HandleEndLocal()268     bool HandleEndLocal()
269     {
270         auto regNumber = ReadRegisterNumber();
271         return handler_->HandleEndLocal(regNumber);
272     }
273 
HandleRestartLocal()274     bool HandleRestartLocal()
275     {
276         auto regNumber = ReadRegisterNumber();
277         return handler_->HandleRestartLocal(regNumber);
278     }
279 
HandleSetColumn()280     bool HandleSetColumn()
281     {
282         auto cn = state_->ReadULeb128();
283         return handler_->HandleSetColumn(cn);
284     }
285 
HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode)286     bool HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode)
287     {
288         ASSERT(static_cast<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE);
289 
290         auto adjustOpcode = static_cast<int32_t>(static_cast<uint8_t>(opcode) - LineNumberProgramItem::OPCODE_BASE);
291         auto pcOffset = static_cast<uint32_t>(adjustOpcode / LineNumberProgramItem::LINE_RANGE);
292         int32_t lineOffset = adjustOpcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE;
293         return handler_->HandleSpecialOpcode(pcOffset, lineOffset);
294     }
295 
296     LineProgramState *state_;
297     const uint8_t *program_;
298     Handler *handler_;
299 };
300 
301 }  // namespace ark::panda_file
302 
303 #endif  // LIBPANDAFILE_LINE_NUMBER_PROGRAM_H
304