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_HELPERS_H
17#define LIBPANDAFILE_DEBUG_HELPERS_H
18
19#include "debug_data_accessor-inl.h"
20#include "file.h"
21#include "file_items.h"
22#include "method_data_accessor-inl.h"
23#include "line_number_program.h"
24#include "libpandabase/utils/span.h"
25
26namespace panda::panda_file::debug_helpers {
27
28class BytecodeOffsetResolver {
29public:
30    BytecodeOffsetResolver(panda_file::LineProgramState *state, uint32_t bc_offset)
31        : state_(state), bc_offset_(bc_offset), prev_line_(state->GetLine()), line_(0)
32    {
33    }
34
35    ~BytecodeOffsetResolver() = default;
36
37    DEFAULT_MOVE_SEMANTIC(BytecodeOffsetResolver);
38    DEFAULT_COPY_SEMANTIC(BytecodeOffsetResolver);
39
40    panda_file::LineProgramState *GetState() const
41    {
42        return state_;
43    }
44
45    uint32_t GetLine() const
46    {
47        return line_;
48    }
49
50    void ProcessBegin() const {}
51
52    void ProcessEnd()
53    {
54        if (line_ == 0) {
55            line_ = state_->GetLine();
56        }
57    }
58
59    bool HandleAdvanceLine(int32_t line_diff) const
60    {
61        state_->AdvanceLine(line_diff);
62        return true;
63    }
64
65    bool HandleAdvancePc(uint32_t pc_diff) const
66    {
67        state_->AdvancePc(pc_diff);
68        return true;
69    }
70
71    bool HandleSetFile([[maybe_unused]] uint32_t source_file_id) const
72    {
73        return true;
74    }
75
76    bool HandleSetSourceCode([[maybe_unused]] uint32_t source_code_id) const
77    {
78        return true;
79    }
80
81    bool HandleSetPrologueEnd() const
82    {
83        return true;
84    }
85
86    bool HandleSetEpilogueBegin() const
87    {
88        return true;
89    }
90
91    bool HandleStartLocal([[maybe_unused]] int32_t reg_number, [[maybe_unused]] uint32_t name_id,
92                          [[maybe_unused]] uint32_t type_id) const
93    {
94        return true;
95    }
96
97    bool HandleStartLocalExtended([[maybe_unused]] int32_t reg_number, [[maybe_unused]] uint32_t name_id,
98                                  [[maybe_unused]] uint32_t type_id, [[maybe_unused]] uint32_t type_signature_id) const
99    {
100        return true;
101    }
102
103    bool HandleEndLocal([[maybe_unused]] int32_t reg_number) const
104    {
105        return true;
106    }
107
108    bool HandleSetColumn([[maybe_unused]] int32_t column_number) const
109    {
110        return true;
111    }
112
113    bool HandleSpecialOpcode(uint32_t pc_offset, int32_t line_offset)
114    {
115        state_->AdvancePc(pc_offset);
116        state_->AdvanceLine(line_offset);
117
118        if (state_->GetAddress() == bc_offset_) {
119            line_ = state_->GetLine();
120            return false;
121        }
122
123        if (state_->GetAddress() > bc_offset_) {
124            line_ = prev_line_;
125            return false;
126        }
127
128        prev_line_ = state_->GetLine();
129
130        return true;
131    }
132
133private:
134    panda_file::LineProgramState *state_;
135    uint32_t bc_offset_;
136    uint32_t prev_line_;
137    uint32_t line_;
138};
139
140inline size_t GetLineNumber(panda::panda_file::MethodDataAccessor mda, uint32_t bc_offset,
141                            const panda::panda_file::File *panda_debug_file)
142{
143    auto debug_info_id = mda.GetDebugInfoId();
144    if (!debug_info_id) {
145        return -1;
146    }
147
148    panda::panda_file::DebugInfoDataAccessor dda(*panda_debug_file, debug_info_id.value());
149    const uint8_t *program = dda.GetLineNumberProgram();
150
151    panda::panda_file::LineProgramState state(*panda_debug_file, panda::panda_file::File::EntityId(0),
152                                              dda.GetLineStart(), dda.GetConstantPool());
153
154    BytecodeOffsetResolver resolver(&state, bc_offset);
155    panda::panda_file::LineNumberProgramProcessor<BytecodeOffsetResolver> program_processor(program, &resolver);
156    program_processor.Process();
157
158    return resolver.GetLine();
159}
160
161}  // namespace panda::panda_file::debug_helpers
162
163#endif  // LIBPANDAFILE_DEBUG_HELPERS_H
164