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