• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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