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_DEBUG_INFO_UPDATER_INL_H 17 #define LIBPANDAFILE_DEBUG_INFO_UPDATER_INL_H 18 19 #include <type_traits> 20 #include "debug_data_accessor.h" 21 #include "debug_data_accessor-inl.h" 22 #include "line_number_program.h" 23 24 namespace panda::panda_file { 25 26 /* T is a CRTP with following methods: 27 * StringItem *GetOrCreateStringItem(const std::string &s) 28 * BaseClassItem *GetType(File::EntityId type_id, const std::string &type_name) 29 */ 30 template <typename T> 31 class DebugInfoUpdater { 32 public: DebugInfoUpdater(const File * file)33 explicit DebugInfoUpdater(const File *file) : file_(file) {} 34 Scrap(File::EntityId debugInfoId)35 void Scrap(File::EntityId debugInfoId) 36 { 37 DebugInfoDataAccessor debugAcc(*file_, debugInfoId); 38 const uint8_t *program = debugAcc.GetLineNumberProgram(); 39 auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size(); 40 auto opcodeSp = Span(program, size); 41 42 size_t i = 0; 43 LineNumberProgramItem::Opcode opcode; 44 panda_file::LineProgramState state(*file_, File::EntityId(0), debugAcc.GetLineStart(), 45 debugAcc.GetConstantPool()); 46 while ((opcode = LineNumberProgramItem::Opcode(opcodeSp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) { 47 switch (opcode) { 48 case LineNumberProgramItem::Opcode::ADVANCE_PC: 49 case LineNumberProgramItem::Opcode::ADVANCE_LINE: 50 case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: 51 case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: { 52 break; 53 } 54 case LineNumberProgramItem::Opcode::START_LOCAL: { 55 [[maybe_unused]] int32_t regNumber; 56 size_t n; 57 bool isFull; 58 std::tie(regNumber, n, isFull) = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 59 LOG_IF(!isFull, FATAL, COMMON) << "Cannot read a register number"; 60 i += n; 61 62 auto nameId = File::EntityId(state.ReadULeb128()); 63 std::string name = utf::Mutf8AsCString(file_->GetStringData(nameId).data); 64 This()->GetOrCreateStringItem(name); 65 66 auto typeId = File::EntityId(state.ReadULeb128()); 67 std::string typeName = utf::Mutf8AsCString(file_->GetStringData(typeId).data); 68 This()->GetType(typeId, typeName); 69 break; 70 } 71 case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: { 72 [[maybe_unused]] int32_t regNumber; 73 size_t n; 74 bool isFull; 75 std::tie(regNumber, n, isFull) = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 76 LOG_IF(!isFull, FATAL, COMMON) << "Cannot read a register number"; 77 i += n; 78 79 auto nameId = File::EntityId(state.ReadULeb128()); 80 std::string name = utf::Mutf8AsCString(file_->GetStringData(nameId).data); 81 This()->GetOrCreateStringItem(name); 82 83 auto typeId = File::EntityId(state.ReadULeb128()); 84 std::string typeName = utf::Mutf8AsCString(file_->GetStringData(typeId).data); 85 This()->GetType(typeId, typeName); 86 87 auto typeSignatureId = File::EntityId(state.ReadULeb128()); 88 std::string typeSignature = utf::Mutf8AsCString(file_->GetStringData(typeSignatureId).data); 89 This()->GetOrCreateStringItem(typeSignature); 90 break; 91 } 92 case LineNumberProgramItem::Opcode::END_LOCAL: 93 case LineNumberProgramItem::Opcode::RESTART_LOCAL: { 94 [[maybe_unused]] int32_t regNumber; 95 size_t n; 96 bool isFull; 97 std::tie(regNumber, n, isFull) = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 98 LOG_IF(!isFull, FATAL, COMMON) << "Cannot read a register number"; 99 i += n; 100 break; 101 } 102 case LineNumberProgramItem::Opcode::SET_FILE: { 103 auto sourceFileId = File::EntityId(state.ReadULeb128()); 104 std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId).data); 105 This()->GetOrCreateStringItem(sourceFile); 106 break; 107 } 108 case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: { 109 auto sourceCodeId = File::EntityId(state.ReadULeb128()); 110 std::string sourceCode = utf::Mutf8AsCString(file_->GetStringData(sourceCodeId).data); 111 This()->GetOrCreateStringItem(sourceCode); 112 break; 113 } 114 default: { 115 break; 116 } 117 } 118 } 119 } 120 Emit(DebugInfoItem * debugInfoItem,File::EntityId debugInfoId)121 void Emit(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId) 122 { 123 auto *lnpItem = debugInfoItem->GetLineNumberProgram(); 124 if (!lnpItem->GetData().empty()) { 125 return; 126 } 127 128 DebugInfoDataAccessor debugAcc(*file_, debugInfoId); 129 const uint8_t *program = debugAcc.GetLineNumberProgram(); 130 auto size = file_->GetSpanFromId(file_->GetIdFromPointer(program)).size(); 131 auto opcodeSp = Span(program, size); 132 133 size_t i = 0; 134 LineNumberProgramItem::Opcode opcode; 135 panda_file::LineProgramState state(*file_, File::EntityId(0), debugAcc.GetLineStart(), 136 debugAcc.GetConstantPool()); 137 while ((opcode = LineNumberProgramItem::Opcode(opcodeSp[i++])) != LineNumberProgramItem::Opcode::END_SEQUENCE) { 138 switch (opcode) { 139 case LineNumberProgramItem::Opcode::ADVANCE_PC: { 140 lnpItem->EmitAdvancePc(debugInfoItem->GetConstantPool(), state.ReadULeb128()); 141 break; 142 } 143 case LineNumberProgramItem::Opcode::ADVANCE_LINE: { 144 lnpItem->EmitAdvanceLine(debugInfoItem->GetConstantPool(), state.ReadSLeb128()); 145 break; 146 } 147 case LineNumberProgramItem::Opcode::START_LOCAL: { 148 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 149 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; 150 i += n; 151 152 auto nameId = File::EntityId(state.ReadULeb128()); 153 std::string name = utf::Mutf8AsCString(file_->GetStringData(nameId).data); 154 auto *nameItem = This()->GetOrCreateStringItem(name); 155 156 auto typeId = File::EntityId(state.ReadULeb128()); 157 std::string typeName = utf::Mutf8AsCString(file_->GetStringData(typeId).data); 158 auto *typeItem = This()->GetType(typeId, typeName); 159 160 lnpItem->EmitStartLocal(debugInfoItem->GetConstantPool(), reg_number, nameItem, 161 typeItem->GetNameItem()); 162 break; 163 } 164 case LineNumberProgramItem::Opcode::START_LOCAL_EXTENDED: { 165 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 166 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; 167 i += n; 168 169 auto nameId = File::EntityId(state.ReadULeb128()); 170 std::string name = utf::Mutf8AsCString(file_->GetStringData(nameId).data); 171 auto *nameItem = This()->GetOrCreateStringItem(name); 172 173 auto typeId = File::EntityId(state.ReadULeb128()); 174 std::string typeName = utf::Mutf8AsCString(file_->GetStringData(typeId).data); 175 auto *typeItem = This()->GetType(typeId, typeName); 176 177 auto typeSignatureId = File::EntityId(state.ReadULeb128()); 178 std::string typeSignature = utf::Mutf8AsCString(file_->GetStringData(typeSignatureId).data); 179 auto *typeSignatureItem = This()->GetOrCreateStringItem(typeSignature); 180 181 lnpItem->EmitStartLocalExtended(debugInfoItem->GetConstantPool(), reg_number, nameItem, 182 typeItem->GetNameItem(), typeSignatureItem); 183 break; 184 } 185 case LineNumberProgramItem::Opcode::END_LOCAL: { 186 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 187 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; 188 i += n; 189 190 lnpItem->EmitEndLocal(reg_number); 191 break; 192 } 193 case LineNumberProgramItem::Opcode::RESTART_LOCAL: { 194 auto [reg_number, n, is_full] = leb128::DecodeSigned<int32_t>(&opcodeSp[i]); 195 LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; 196 i += n; 197 198 lnpItem->EmitRestartLocal(reg_number); 199 break; 200 } 201 case LineNumberProgramItem::Opcode::SET_PROLOGUE_END: { 202 lnpItem->EmitPrologEnd(); 203 break; 204 } 205 case LineNumberProgramItem::Opcode::SET_EPILOGUE_BEGIN: { 206 lnpItem->EmitEpilogBegin(); 207 break; 208 } 209 case LineNumberProgramItem::Opcode::SET_FILE: { 210 auto sourceFileId = File::EntityId(state.ReadULeb128()); 211 std::string sourceFile = utf::Mutf8AsCString(file_->GetStringData(sourceFileId).data); 212 auto *sourceFileItem = This()->GetOrCreateStringItem(sourceFile); 213 lnpItem->EmitSetFile(debugInfoItem->GetConstantPool(), sourceFileItem); 214 break; 215 } 216 case LineNumberProgramItem::Opcode::SET_SOURCE_CODE: { 217 auto sourceCodeId = File::EntityId(state.ReadULeb128()); 218 std::string sourceCode = utf::Mutf8AsCString(file_->GetStringData(sourceCodeId).data); 219 auto *sourceCodeItem = This()->GetOrCreateStringItem(sourceCode); 220 lnpItem->EmitSetSourceCode(debugInfoItem->GetConstantPool(), sourceCodeItem); 221 break; 222 } 223 case LineNumberProgramItem::Opcode::SET_COLUMN: { 224 lnpItem->EmitColumn(debugInfoItem->GetConstantPool(), 0, state.ReadULeb128()); 225 break; 226 } 227 default: { 228 auto opcodeValue = static_cast<uint8_t>(opcode); 229 auto adjustOpcode = opcodeValue - LineNumberProgramItem::OPCODE_BASE; 230 uint32_t pcDiff = adjustOpcode / LineNumberProgramItem::LINE_RANGE; 231 int32_t lineDiff = 232 adjustOpcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; 233 lnpItem->EmitSpecialOpcode(pcDiff, lineDiff); 234 break; 235 } 236 } 237 } 238 lnpItem->EmitEnd(); 239 } 240 241 protected: GetFile()242 const File *GetFile() const 243 { 244 return file_; 245 } 246 247 private: 248 const File *file_; 249 This()250 T *This() 251 { 252 static_assert(std::is_base_of_v<DebugInfoUpdater, T>); 253 return static_cast<T *>(this); 254 } 255 }; 256 } // namespace panda::panda_file 257 258 #endif // LIBPANDAFILE_DEBUG_INFO_UPDATER_INL_H 259