Home | History | Annotate | Download | only in slicer
      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 
     25 bool DebugInfoEncoder::Visit(DbgInfoHeader* dbg_header) {
     26   assert(param_names_ == nullptr);
     27   param_names_ = &dbg_header->param_names;
     28   return true;
     29 }
     30 
     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 
    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