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_PROGRAMH 17 #define LIBPANDAFILE_LINE_NUMBER_PROGRAMH 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,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 case Opcode::SET_EPILOGUE_BEGIN: 157 break; 158 case Opcode::START_LOCAL: { 159 res = HandleStartLocal(); 160 break; 161 } 162 case Opcode::START_LOCAL_EXTENDED: { 163 res = HandleStartLocalExtended(); 164 break; 165 } 166 case Opcode::RESTART_LOCAL: { 167 LOG(FATAL, PANDAFILE) << "Opcode RESTART_LOCAL is not supported"; 168 break; 169 } 170 case Opcode::END_LOCAL: { 171 res = HandleEndLocal(); 172 break; 173 } 174 case Opcode::SET_COLUMN: { 175 res = HandleSetColumn(); 176 break; 177 } 178 default: { 179 res = HandleSpecialOpcode(opcode); 180 break; 181 } 182 } 183 184 if (!res) { 185 break; 186 } 187 188 opcode = ReadOpcode(); 189 } 190 191 handler_->ProcessEnd(); 192 } 193 194 private: 195 using Opcode = LineNumberProgramItem::Opcode; 196 ReadOpcode()197 Opcode ReadOpcode() 198 { 199 auto opcode = static_cast<Opcode>(*program_); 200 ++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 201 return opcode; 202 } 203 ReadRegisterNumber()204 int32_t ReadRegisterNumber() 205 { 206 auto [regiser_number, n, is_full] = leb128::DecodeSigned<int32_t>(program_); 207 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; 208 program_ += n; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 209 return regiser_number; 210 } 211 HandleAdvanceLine()212 bool HandleAdvanceLine() const 213 { 214 auto lineDiff = state_->ReadSLeb128(); 215 return handler_->HandleAdvanceLine(lineDiff); 216 } 217 HandleAdvancePc()218 bool HandleAdvancePc() const 219 { 220 auto pcDiff = state_->ReadULeb128(); 221 return handler_->HandleAdvancePc(pcDiff); 222 } 223 HandleSetFile()224 bool HandleSetFile() const 225 { 226 return handler_->HandleSetFile(state_->ReadULeb128()); 227 } 228 HandleSetSourceCode()229 bool HandleSetSourceCode() const 230 { 231 return handler_->HandleSetSourceCode(state_->ReadULeb128()); 232 } 233 HandleSetPrologueEnd()234 bool HandleSetPrologueEnd() const 235 { 236 return handler_->HandleSetPrologueEnd(); 237 } 238 HandleSetEpilogueBegin()239 bool HandleSetEpilogueBegin() const 240 { 241 return handler_->HandleSetEpilogueBegin(); 242 } 243 HandleStartLocal()244 bool HandleStartLocal() 245 { 246 auto regNumber = ReadRegisterNumber(); 247 auto nameIndex = state_->ReadULeb128(); 248 auto typeIndex = state_->ReadULeb128(); 249 return handler_->HandleStartLocal(regNumber, nameIndex, typeIndex); 250 } 251 HandleStartLocalExtended()252 bool HandleStartLocalExtended() 253 { 254 auto regNumber = ReadRegisterNumber(); 255 auto nameIndex = state_->ReadULeb128(); 256 auto typeIndex = state_->ReadULeb128(); 257 auto typeSignatureIndex = state_->ReadULeb128(); 258 return handler_->HandleStartLocalExtended(regNumber, nameIndex, typeIndex, typeSignatureIndex); 259 } 260 HandleEndLocal()261 bool HandleEndLocal() 262 { 263 auto regNumber = ReadRegisterNumber(); 264 return handler_->HandleEndLocal(regNumber); 265 } 266 HandleSetColumn()267 bool HandleSetColumn() 268 { 269 auto cn = state_->ReadULeb128(); 270 return handler_->HandleSetColumn(cn); 271 } 272 HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode)273 bool HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode) 274 { 275 ASSERT(static_cast<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE); 276 277 auto adjustOpcode = static_cast<int32_t>(static_cast<uint8_t>(opcode) - LineNumberProgramItem::OPCODE_BASE); 278 auto pcOffset = static_cast<uint32_t>(adjustOpcode / LineNumberProgramItem::LINE_RANGE); 279 int32_t lineOffset = adjustOpcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; 280 return handler_->HandleSpecialOpcode(pcOffset, lineOffset); 281 } 282 283 LineProgramState *state_; 284 const uint8_t *program_; 285 Handler *handler_; 286 }; 287 288 } // namespace panda::panda_file 289 290 #endif // LIBPANDAFILE_LINE_NUMBER_PROGRAM_H 291