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