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