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