1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "slicer/debuginfo_encoder.h"
18
19 #include "slicer/common.h"
20
21 #include <assert.h>
22 #include <sstream>
23 #include <iomanip>
24
25
26 namespace lir {
27
Visit(DbgInfoHeader * dbg_header)28 bool DebugInfoEncoder::Visit(DbgInfoHeader* dbg_header) {
29 assert(param_names_ == nullptr);
30 param_names_ = &dbg_header->param_names;
31 return true;
32 }
33
Visit(DbgInfoAnnotation * dbg_annotation)34 bool DebugInfoEncoder::Visit(DbgInfoAnnotation* dbg_annotation) {
35 // keep the address in sync
36 if (last_address_ != dbg_annotation->offset) {
37 SLICER_CHECK_GT(dbg_annotation->offset, last_address_);
38 dbginfo_.Push<dex::u1>(dex::DBG_ADVANCE_PC);
39 dbginfo_.PushULeb128(dbg_annotation->offset - last_address_);
40 last_address_ = dbg_annotation->offset;
41 }
42
43 // encode the annotation itself
44 switch (dbg_annotation->dbg_opcode) {
45 case dex::DBG_ADVANCE_LINE: {
46 // DBG_ANDVANCE_LINE is used a bit differently in the code IR
47 // vs the .dex image: the code IR uses it exclusively for source
48 // location (the .line directive) while .dex format uses it to
49 // advance the "line" register without emitting a "position entry"
50 int line = dbg_annotation->CastOperand<LineNumber>(0)->line;
51 if (line_start_ == 0) {
52 // it's not perfectly clear from the .dex specification
53 // if initial line == 0 is valid, but a number of existing
54 // .dex files do this so we have to support it
55 SLICER_CHECK_GE(line, 0);
56 line_start_ = line;
57 } else {
58 SLICER_WEAK_CHECK(line > 0);
59 int delta = line - last_line_;
60 int adj_opcode = delta - dex::DBG_LINE_BASE;
61 // out of range for special opcode?
62 if (adj_opcode < 0 || adj_opcode >= dex::DBG_LINE_RANGE) {
63 dbginfo_.Push<dex::u1>(dex::DBG_ADVANCE_LINE);
64 dbginfo_.PushSLeb128(delta);
65 adj_opcode = -dex::DBG_LINE_BASE;
66 }
67 assert(adj_opcode >= 0 && dex::DBG_FIRST_SPECIAL + adj_opcode < 256);
68 dex::u1 special_opcode = dex::DBG_FIRST_SPECIAL + adj_opcode;
69 dbginfo_.Push<dex::u1>(special_opcode);
70 }
71 last_line_ = line;
72 } break;
73
74 case dex::DBG_START_LOCAL: {
75 auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
76 auto name_index = dbg_annotation->CastOperand<String>(1)->index;
77 auto type_index = dbg_annotation->CastOperand<Type>(2)->index;
78 dbginfo_.Push<dex::u1>(dex::DBG_START_LOCAL);
79 dbginfo_.PushULeb128(reg);
80 dbginfo_.PushULeb128(name_index + 1);
81 dbginfo_.PushULeb128(type_index + 1);
82 } break;
83
84 case dex::DBG_START_LOCAL_EXTENDED: {
85 auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
86 auto name_index = dbg_annotation->CastOperand<String>(1)->index;
87 auto type_index = dbg_annotation->CastOperand<Type>(2)->index;
88 auto sig_index = dbg_annotation->CastOperand<String>(3)->index;
89 dbginfo_.Push<dex::u1>(dex::DBG_START_LOCAL_EXTENDED);
90 dbginfo_.PushULeb128(reg);
91 dbginfo_.PushULeb128(name_index + 1);
92 dbginfo_.PushULeb128(type_index + 1);
93 dbginfo_.PushULeb128(sig_index + 1);
94 } break;
95
96 case dex::DBG_END_LOCAL:
97 case dex::DBG_RESTART_LOCAL: {
98 auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
99 dbginfo_.Push<dex::u1>(dbg_annotation->dbg_opcode);
100 dbginfo_.PushULeb128(reg);
101 } break;
102
103 case dex::DBG_SET_PROLOGUE_END:
104 case dex::DBG_SET_EPILOGUE_BEGIN:
105 dbginfo_.Push<dex::u1>(dbg_annotation->dbg_opcode);
106 break;
107
108 case dex::DBG_SET_FILE: {
109 auto file_name = dbg_annotation->CastOperand<String>(0);
110 if (file_name->ir_string != source_file_) {
111 source_file_ = file_name->ir_string;
112 dbginfo_.Push<dex::u1>(dex::DBG_SET_FILE);
113 dbginfo_.PushULeb128(file_name->index + 1);
114 }
115 } break;
116
117 default: {
118 std::stringstream ss;
119 ss << "Unexpected debug info opcode: " << dbg_annotation->dbg_opcode;
120 SLICER_FATAL(ss.str());
121 }
122 }
123
124 return true;
125 }
126
Encode(ir::EncodedMethod * ir_method,std::shared_ptr<ir::DexFile> dex_ir)127 void DebugInfoEncoder::Encode(ir::EncodedMethod* ir_method, std::shared_ptr<ir::DexFile> dex_ir) {
128 auto ir_debug_info = ir_method->code->debug_info;
129
130 SLICER_CHECK(dbginfo_.empty());
131 SLICER_CHECK_EQ(param_names_, nullptr);
132 SLICER_CHECK_EQ(line_start_, 0);
133 SLICER_CHECK_EQ(last_line_, 0);
134 SLICER_CHECK_EQ(last_address_, 0);
135 SLICER_CHECK_EQ(source_file_, nullptr);
136
137 // generate new debug info
138 source_file_ = ir_method->decl->parent->class_def->source_file;
139 for (auto instr : instructions_) {
140 instr->Accept(this);
141 }
142 dbginfo_.Push<dex::u1>(dex::DBG_END_SEQUENCE);
143 dbginfo_.Seal(1);
144
145 SLICER_CHECK(!dbginfo_.empty());
146
147 // update ir::DebugInfo
148 ir_debug_info->line_start = line_start_;
149 ir_debug_info->data = slicer::MemView(dbginfo_.data(), dbginfo_.size());
150
151 if (param_names_ != nullptr) {
152 ir_debug_info->param_names = *param_names_;
153 } else {
154 ir_debug_info->param_names = {};
155 }
156
157 // attach the debug info buffer to the dex IR
158 dex_ir->AttachBuffer(std::move(dbginfo_));
159 }
160
161 } // namespace lir
162