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/common.h"
18 #include "slicer/debuginfo_encoder.h"
19 #include "slicer/chronometer.h"
20 
21 #include <assert.h>
22 
23 namespace lir {
24 
Visit(DbgInfoHeader * dbg_header)25 bool DebugInfoEncoder::Visit(DbgInfoHeader* dbg_header) {
26   assert(param_names_ == nullptr);
27   param_names_ = &dbg_header->param_names;
28   return true;
29 }
30 
Visit(DbgInfoAnnotation * dbg_annotation)31 bool DebugInfoEncoder::Visit(DbgInfoAnnotation* dbg_annotation) {
32   // keep the address in sync
33   if (last_address_ != dbg_annotation->offset) {
34     SLICER_CHECK(dbg_annotation->offset > last_address_);
35     dbginfo_.Push<dex::u1>(dex::DBG_ADVANCE_PC);
36     dbginfo_.PushULeb128(dbg_annotation->offset - last_address_);
37     last_address_ = dbg_annotation->offset;
38   }
39 
40   // encode the annotation itself
41   switch (dbg_annotation->dbg_opcode) {
42     case dex::DBG_ADVANCE_LINE: {
43       // DBG_ANDVANCE_LINE is used a bit differently in the code IR
44       // vs the .dex image: the code IR uses it exclusively for source
45       // location (the .line directive) while .dex format uses it to
46       // advance the "line" register without emitting a "position entry"
47       int line = dbg_annotation->CastOperand<LineNumber>(0)->line;
48       if (line_start_ == 0) {
49         // it's not perfectly clear from the .dex specification
50         // if initial line == 0 is valid, but a number of existing
51         // .dex files do this so we have to support it
52         SLICER_CHECK(line >= 0);
53         line_start_ = line;
54       } else {
55         SLICER_WEAK_CHECK(line > 0);
56         int delta = line - last_line_;
57         int adj_opcode = delta - dex::DBG_LINE_BASE;
58         // out of range for special opcode?
59         if (adj_opcode < 0 || adj_opcode >= dex::DBG_LINE_RANGE) {
60           dbginfo_.Push<dex::u1>(dex::DBG_ADVANCE_LINE);
61           dbginfo_.PushSLeb128(delta);
62           adj_opcode = -dex::DBG_LINE_BASE;
63         }
64         assert(adj_opcode >= 0 && dex::DBG_FIRST_SPECIAL + adj_opcode < 256);
65         dex::u1 special_opcode = dex::DBG_FIRST_SPECIAL + adj_opcode;
66         dbginfo_.Push<dex::u1>(special_opcode);
67       }
68       last_line_ = line;
69     } break;
70 
71     case dex::DBG_START_LOCAL: {
72       auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
73       auto name_index = dbg_annotation->CastOperand<String>(1)->index;
74       auto type_index = dbg_annotation->CastOperand<Type>(2)->index;
75       dbginfo_.Push<dex::u1>(dex::DBG_START_LOCAL);
76       dbginfo_.PushULeb128(reg);
77       dbginfo_.PushULeb128(name_index + 1);
78       dbginfo_.PushULeb128(type_index + 1);
79     } break;
80 
81     case dex::DBG_START_LOCAL_EXTENDED: {
82       auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
83       auto name_index = dbg_annotation->CastOperand<String>(1)->index;
84       auto type_index = dbg_annotation->CastOperand<Type>(2)->index;
85       auto sig_index = dbg_annotation->CastOperand<String>(3)->index;
86       dbginfo_.Push<dex::u1>(dex::DBG_START_LOCAL_EXTENDED);
87       dbginfo_.PushULeb128(reg);
88       dbginfo_.PushULeb128(name_index + 1);
89       dbginfo_.PushULeb128(type_index + 1);
90       dbginfo_.PushULeb128(sig_index + 1);
91     } break;
92 
93     case dex::DBG_END_LOCAL:
94     case dex::DBG_RESTART_LOCAL: {
95       auto reg = dbg_annotation->CastOperand<VReg>(0)->reg;
96       dbginfo_.Push<dex::u1>(dbg_annotation->dbg_opcode);
97       dbginfo_.PushULeb128(reg);
98     } break;
99 
100     case dex::DBG_SET_PROLOGUE_END:
101     case dex::DBG_SET_EPILOGUE_BEGIN:
102       dbginfo_.Push<dex::u1>(dbg_annotation->dbg_opcode);
103       break;
104 
105     case dex::DBG_SET_FILE: {
106       auto file_name = dbg_annotation->CastOperand<String>(0);
107       if (file_name->ir_string != source_file_) {
108         source_file_ = file_name->ir_string;
109         dbginfo_.Push<dex::u1>(dex::DBG_SET_FILE);
110         dbginfo_.PushULeb128(file_name->index + 1);
111       }
112     } break;
113 
114     default:
115       SLICER_FATAL("Unexpected debug info opcode: 0x%02x", dbg_annotation->dbg_opcode);
116   }
117 
118   return true;
119 }
120 
Encode(ir::EncodedMethod * ir_method,std::shared_ptr<ir::DexFile> dex_ir)121 void DebugInfoEncoder::Encode(ir::EncodedMethod* ir_method, std::shared_ptr<ir::DexFile> dex_ir) {
122   auto ir_debug_info = ir_method->code->debug_info;
123 
124   SLICER_CHECK(dbginfo_.empty());
125   SLICER_CHECK(param_names_ == nullptr);
126   SLICER_CHECK(line_start_ == 0);
127   SLICER_CHECK(last_line_ == 0);
128   SLICER_CHECK(last_address_ == 0);
129   SLICER_CHECK(source_file_ == nullptr);
130 
131   // generate new debug info
132   source_file_ = ir_method->decl->parent->class_def->source_file;
133   for (auto instr : instructions_) {
134     instr->Accept(this);
135   }
136   dbginfo_.Push<dex::u1>(dex::DBG_END_SEQUENCE);
137   dbginfo_.Seal(1);
138 
139   SLICER_CHECK(!dbginfo_.empty());
140 
141   // update ir::DebugInfo
142   ir_debug_info->line_start = line_start_;
143   ir_debug_info->data = slicer::MemView(dbginfo_.data(), dbginfo_.size());
144 
145   if (param_names_ != nullptr) {
146     ir_debug_info->param_names = *param_names_;
147   } else {
148     ir_debug_info->param_names = {};
149   }
150 
151   // attach the debug info buffer to the dex IR
152   dex_ir->AttachBuffer(std::move(dbginfo_));
153 }
154 
155 }  // namespace lir
156