• 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 
Process()131     void Process()
132     {
133         handler_->ProcessBegin();
134 
135         auto opcode = ReadOpcode();
136         bool res = false;
137         while (opcode != Opcode::END_SEQUENCE) {
138             switch (opcode) {
139                 case Opcode::ADVANCE_LINE: {
140                     res = HandleAdvanceLine();
141                     break;
142                 }
143                 case Opcode::ADVANCE_PC: {
144                     res = HandleAdvancePc();
145                     break;
146                 }
147                 case Opcode::SET_FILE: {
148                     res = HandleSetFile();
149                     break;
150                 }
151                 case Opcode::SET_SOURCE_CODE: {
152                     res = HandleSetSourceCode();
153                     break;
154                 }
155                 case Opcode::SET_PROLOGUE_END: {
156                     res = HandleSetPrologueEnd();
157                     break;
158                 }
159                 case Opcode::SET_EPILOGUE_BEGIN: {
160                     res = HandleSetEpilogueBegin();
161                     break;
162                 }
163                 case Opcode::START_LOCAL: {
164                     res = HandleStartLocal();
165                     break;
166                 }
167                 case Opcode::START_LOCAL_EXTENDED: {
168                     res = HandleStartLocalExtended();
169                     break;
170                 }
171                 case Opcode::RESTART_LOCAL: {
172                     res = HandleRestartLocal();
173                     break;
174                 }
175                 case Opcode::END_LOCAL: {
176                     res = HandleEndLocal();
177                     break;
178                 }
179                 case Opcode::SET_COLUMN: {
180                     res = HandleSetColumn();
181                     break;
182                 }
183                 default: {
184                     res = HandleSpecialOpcode(opcode);
185                     break;
186                 }
187             }
188 
189             if (!res) {
190                 break;
191             }
192 
193             opcode = ReadOpcode();
194         }
195 
196         handler_->ProcessEnd();
197     }
198 
199 private:
200     using Opcode = LineNumberProgramItem::Opcode;
201 
ReadOpcode()202     Opcode ReadOpcode()
203     {
204         auto opcode = static_cast<Opcode>(*program_);
205         ++program_;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
206         return opcode;
207     }
208 
ReadRegisterNumber()209     int32_t ReadRegisterNumber()
210     {
211         auto [regiserNumber, n, isFull] = leb128::DecodeSigned<int32_t>(program_);
212         LOG_IF(!isFull, FATAL, COMMON) << "Cannot read a register number";
213         program_ += n;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
214         return regiserNumber;
215     }
216 
HandleAdvanceLine()217     bool HandleAdvanceLine() const
218     {
219         auto lineDiff = state_->ReadSLeb128();
220         return handler_->HandleAdvanceLine(lineDiff);
221     }
222 
HandleAdvancePc()223     bool HandleAdvancePc() const
224     {
225         auto pcDiff = state_->ReadULeb128();
226         return handler_->HandleAdvancePc(pcDiff);
227     }
228 
HandleSetFile()229     bool HandleSetFile() const
230     {
231         return handler_->HandleSetFile(state_->ReadULeb128());
232     }
233 
HandleSetSourceCode()234     bool HandleSetSourceCode() const
235     {
236         return handler_->HandleSetSourceCode(state_->ReadULeb128());
237     }
238 
HandleSetPrologueEnd()239     bool HandleSetPrologueEnd() const
240     {
241         return handler_->HandleSetPrologueEnd();
242     }
243 
HandleSetEpilogueBegin()244     bool HandleSetEpilogueBegin() const
245     {
246         return handler_->HandleSetEpilogueBegin();
247     }
248 
HandleStartLocal()249     bool HandleStartLocal()
250     {
251         auto regNumber = ReadRegisterNumber();
252         auto nameIndex = state_->ReadULeb128();
253         auto typeIndex = state_->ReadULeb128();
254         return handler_->HandleStartLocal(regNumber, nameIndex, typeIndex);
255     }
256 
HandleStartLocalExtended()257     bool HandleStartLocalExtended()
258     {
259         auto regNumber = ReadRegisterNumber();
260         auto nameIndex = state_->ReadULeb128();
261         auto typeIndex = state_->ReadULeb128();
262         auto typeSignatureIndex = state_->ReadULeb128();
263         return handler_->HandleStartLocalExtended(regNumber, nameIndex, typeIndex, typeSignatureIndex);
264     }
265 
HandleEndLocal()266     bool HandleEndLocal()
267     {
268         auto regNumber = ReadRegisterNumber();
269         return handler_->HandleEndLocal(regNumber);
270     }
271 
HandleRestartLocal()272     bool HandleRestartLocal()
273     {
274         auto regNumber = ReadRegisterNumber();
275         return handler_->HandleRestartLocal(regNumber);
276     }
277 
HandleSetColumn()278     bool HandleSetColumn()
279     {
280         auto cn = state_->ReadULeb128();
281         return handler_->HandleSetColumn(cn);
282     }
283 
HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode)284     bool HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode)
285     {
286         ASSERT(static_cast<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE);
287 
288         auto adjustOpcode = static_cast<int32_t>(static_cast<uint8_t>(opcode) - LineNumberProgramItem::OPCODE_BASE);
289         auto pcOffset = static_cast<uint32_t>(adjustOpcode / LineNumberProgramItem::LINE_RANGE);
290         int32_t lineOffset = adjustOpcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE;
291         return handler_->HandleSpecialOpcode(pcOffset, lineOffset);
292     }
293 
294     LineProgramState *state_;
295     const uint8_t *program_;
296     Handler *handler_;
297 };
298 
299 }  // namespace ark::panda_file
300 
301 #endif  // LIBPANDAFILE_LINE_NUMBER_PROGRAM_H
302