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