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