libredex/DexDebugInstruction.cpp (103 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <sstream>
#include "DexAccess.h"
#include "DexClass.h"
#include "DexDebugInstruction.h"
#include "DexDefs.h"
#include "DexIdx.h"
#include "DexOutput.h"
void DexDebugOpcodeSetFile::gather_strings(
std::vector<const DexString*>& lstring) const {
if (m_str) lstring.push_back(m_str);
}
void DexDebugOpcodeSetFile::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
DexDebugInstruction::encode(dodx, encdata);
uint32_t fidx = DEX_NO_INDEX;
if (m_str) {
fidx = dodx->stringidx(m_str);
}
encdata = write_uleb128p1(encdata, fidx);
}
void DexDebugOpcodeStartLocal::gather_strings(
std::vector<const DexString*>& lstring) const {
if (m_name) lstring.push_back(m_name);
if (m_sig) lstring.push_back(m_sig);
}
void DexDebugOpcodeStartLocal::gather_types(
std::vector<DexType*>& ltype) const {
if (m_type) ltype.push_back(m_type);
}
void DexDebugOpcodeStartLocal::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
DexDebugInstruction::encode(dodx, encdata);
uint32_t nidx = DEX_NO_INDEX;
uint32_t tidx = DEX_NO_INDEX;
if (m_name) {
nidx = dodx->stringidx(m_name);
}
if (m_type) {
tidx = dodx->typeidx(m_type);
}
encdata = write_uleb128p1(encdata, nidx);
encdata = write_uleb128p1(encdata, tidx);
if (m_sig) {
encdata = write_uleb128p1(encdata, dodx->stringidx(m_sig));
}
}
void DexDebugInstruction::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
*encdata++ = (uint8_t)m_opcode;
if (m_signed) {
encdata = write_sleb128(encdata, m_value);
return;
}
if (m_uvalue == DEX_NO_INDEX) return;
encdata = write_uleb128(encdata, m_uvalue);
}
DexDebugInstruction* DexDebugInstruction::make_instruction(
DexIdx* idx, const uint8_t** encdata_ptr) {
auto& encdata = *encdata_ptr;
uint8_t opcode = *encdata++;
switch (opcode) {
case DBG_END_SEQUENCE:
return nullptr;
case DBG_ADVANCE_PC:
case DBG_END_LOCAL:
case DBG_RESTART_LOCAL: {
uint32_t v = read_uleb128(&encdata);
return new DexDebugInstruction((DexDebugItemOpcode)opcode, v);
}
case DBG_ADVANCE_LINE: {
int32_t v = (uint32_t)read_sleb128(&encdata);
return new DexDebugInstruction((DexDebugItemOpcode)opcode, v);
}
case DBG_START_LOCAL: {
uint32_t rnum = read_uleb128(&encdata);
auto name = decode_noindexable_string(idx, encdata);
DexType* type = decode_noindexable_type(idx, encdata);
return new DexDebugOpcodeStartLocal(rnum, name, type);
}
case DBG_START_LOCAL_EXTENDED: {
uint32_t rnum = read_uleb128(&encdata);
auto name = decode_noindexable_string(idx, encdata);
DexType* type = decode_noindexable_type(idx, encdata);
auto sig = decode_noindexable_string(idx, encdata);
return new DexDebugOpcodeStartLocal(rnum, name, type, sig);
}
case DBG_SET_FILE: {
auto str = decode_noindexable_string(idx, encdata);
return new DexDebugOpcodeSetFile(str);
}
default:
return new DexDebugInstruction((DexDebugItemOpcode)opcode);
};
}
// Returns a DexDebugInstruction corresponding to emitting a line entry
// with the given address offset and line offset. Asserts if invalid arguments.
std::unique_ptr<DexDebugInstruction> DexDebugInstruction::create_line_entry(
int8_t line, uint8_t addr) {
// These are limits imposed by
// https://source.android.com/devices/tech/dalvik/dex-format#opcodes
always_assert(line >= -4 && line <= 10);
always_assert(addr <= 17);
// Below is correct because adjusted_opcode = (addr * 15) + (line + 4), so
// line_offset = -4 + (adjusted_opcode % 15) = -4 + line + 4 = line
// addr_offset = adjusted_opcode / 15 = addr * 15 / 15 = addr since line + 4
// is bounded by 0 and 14 we know (line + 4) / 15 = 0
uint8_t opcode = 0xa + (addr * 15) + (line + 4);
return std::make_unique<DexDebugInstruction>(
static_cast<DexDebugItemOpcode>(opcode));
}
bool DexDebugInstruction::operator==(const DexDebugInstruction& that) const {
return m_opcode == that.m_opcode && m_signed == that.m_signed &&
(m_signed ? m_value == that.m_value : m_uvalue == that.m_uvalue);
};