libredex/DexAnnotation.cpp (825 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 "DexAnnotation.h"
#include <sstream>
#include "Debug.h"
#include "DexClass.h"
#include "DexIdx.h"
#include "DexOutput.h"
#include "DexUtil.h"
#include "Show.h"
void DexEncodedValueMethodType::gather_strings(
std::vector<const DexString*>& lstring) const {
proto()->gather_strings(lstring);
}
void DexEncodedValueString::gather_strings(
std::vector<const DexString*>& lstring) const {
lstring.push_back(string());
}
void DexEncodedValueType::gather_types(std::vector<DexType*>& ltype) const {
ltype.push_back(type());
}
void DexEncodedValueField::gather_fields(
std::vector<DexFieldRef*>& lfield) const {
lfield.push_back(field());
}
void DexEncodedValueMethod::gather_methods(
std::vector<DexMethodRef*>& lmethod) const {
lmethod.push_back(method());
}
void DexEncodedValueMethodHandle::gather_methods(
std::vector<DexMethodRef*>& lmethod) const {
methodhandle()->gather_methods(lmethod);
}
void DexEncodedValueMethodHandle::gather_fields(
std::vector<DexFieldRef*>& lfield) const {
methodhandle()->gather_fields(lfield);
}
void DexEncodedValueMethodHandle::gather_methodhandles(
std::vector<DexMethodHandle*>& lhandles) const {
lhandles.push_back(methodhandle());
}
void DexEncodedValueArray::gather_strings(
std::vector<const DexString*>& lstring) const {
for (auto& ev : *evalues()) {
ev->gather_strings(lstring);
}
}
void DexEncodedValueArray::gather_types(std::vector<DexType*>& ltype) const {
for (auto& ev : *evalues()) {
ev->gather_types(ltype);
}
}
void DexEncodedValueArray::gather_fields(
std::vector<DexFieldRef*>& lfield) const {
for (auto& ev : *evalues()) {
ev->gather_fields(lfield);
}
}
void DexEncodedValueArray::gather_methods(
std::vector<DexMethodRef*>& lmethod) const {
for (auto& ev : *evalues()) {
ev->gather_methods(lmethod);
}
}
void DexEncodedValueAnnotation::gather_strings(
std::vector<const DexString*>& lstring) const {
for (auto const& elem : m_annotations) {
lstring.push_back(elem.string);
elem.encoded_value->gather_strings(lstring);
}
}
void DexEncodedValueAnnotation::gather_types(
std::vector<DexType*>& ltype) const {
ltype.push_back(m_type);
for (auto const& anno : m_annotations) {
anno.encoded_value->gather_types(ltype);
}
}
void DexEncodedValueAnnotation::gather_fields(
std::vector<DexFieldRef*>& lfield) const {
for (auto const& anno : m_annotations) {
anno.encoded_value->gather_fields(lfield);
}
}
void DexEncodedValueAnnotation::gather_methods(
std::vector<DexMethodRef*>& lmethod) const {
for (auto const& anno : m_annotations) {
anno.encoded_value->gather_methods(lmethod);
}
}
void DexAnnotation::gather_strings(
std::vector<const DexString*>& lstring) const {
for (auto const& anno : m_anno_elems) {
lstring.push_back(anno.string);
anno.encoded_value->gather_strings(lstring);
}
}
void DexAnnotation::gather_types(std::vector<DexType*>& ltype) const {
ltype.push_back(m_type);
for (auto const& anno : m_anno_elems) {
anno.encoded_value->gather_types(ltype);
}
}
void DexAnnotation::gather_fields(std::vector<DexFieldRef*>& lfield) const {
for (auto const& anno : m_anno_elems) {
anno.encoded_value->gather_fields(lfield);
}
}
void DexAnnotation::gather_methods(std::vector<DexMethodRef*>& lmethod) const {
for (auto const& anno : m_anno_elems) {
anno.encoded_value->gather_methods(lmethod);
}
}
void DexAnnotationSet::gather_strings(
std::vector<const DexString*>& lstring) const {
for (auto const& anno : m_annotations) {
anno->gather_strings(lstring);
}
}
void DexAnnotationSet::gather_types(std::vector<DexType*>& ltype) const {
for (auto const& anno : m_annotations) {
anno->gather_types(ltype);
}
}
void DexAnnotationSet::gather_methods(
std::vector<DexMethodRef*>& lmethod) const {
for (auto const& anno : m_annotations) {
anno->gather_methods(lmethod);
}
}
void DexAnnotationSet::gather_fields(std::vector<DexFieldRef*>& lfield) const {
for (auto const& anno : m_annotations) {
anno->gather_fields(lfield);
}
}
uint64_t read_evarg(const uint8_t*& encdata,
uint8_t evarg,
bool sign_extend /* = false */
) {
uint64_t v = *encdata++;
int shift = 8;
while (evarg--) {
v |= uint64_t(*encdata++) << shift;
shift += 8;
}
if (sign_extend) {
v = (int64_t)(v << (64 - shift)) >> (64 - shift);
}
return v;
}
void type_encoder(uint8_t*& encdata, uint8_t type, uint64_t val) {
uint8_t devtb = DEVT_HDR_TYPE(type);
int count = 0;
uint64_t t = (val >> 8);
while (t) {
count++;
t >>= 8;
}
devtb |= TO_DEVT_HDR_ARG(count);
*encdata++ = devtb;
t = (val >> 8);
*encdata++ = val & 0xff;
while (t) {
*encdata++ = t & 0xff;
t >>= 8;
}
}
void type_encoder_signext(uint8_t*& encdata, uint8_t type, uint64_t val) {
uint8_t* mp = encdata++;
int64_t sval = *(int64_t*)&val;
int64_t t = sval;
int bytes = 0;
while (true) {
uint8_t emit = t & 0xff;
int64_t rest = t >> 8;
*encdata++ = emit;
bytes++;
if (rest == 0) {
if ((emit & 0x80) == 0) break;
}
if (rest == -1) {
if ((emit & 0x80) == 0x80) break;
}
t = rest;
}
*mp = DEVT_HDR_TYPE(type) | TO_DEVT_HDR_ARG(bytes - 1);
}
void type_encoder_fp(uint8_t*& encdata, uint8_t type, uint64_t val) {
// Ignore trailing zero bytes.
int bytes = 0;
while (val && ((val & 0xff) == 0)) {
val >>= 8;
bytes++;
}
int encbytes;
switch (type) {
case DEVT_FLOAT:
encbytes = 4 - bytes;
break;
case DEVT_DOUBLE:
encbytes = 8 - bytes;
break;
default:
not_reached();
}
if (val == 0) {
encbytes = 1;
}
// Encode.
*encdata++ = DEVT_HDR_TYPE(type) | TO_DEVT_HDR_ARG(encbytes - 1);
for (int i = 0; i < encbytes; i++) {
*encdata++ = val & 0xff;
val >>= 8;
}
}
void DexEncodedValue::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
switch (m_evtype) {
case DEVT_SHORT:
case DEVT_INT:
case DEVT_LONG:
type_encoder_signext(encdata, m_evtype, m_val.m_value);
return;
case DEVT_FLOAT:
case DEVT_DOUBLE:
type_encoder_fp(encdata, m_evtype, m_val.m_value);
return;
default:
// TOOD: Should this really be here?
type_encoder(encdata, m_evtype, as_value());
return;
}
}
void DexEncodedValue::vencode(DexOutputIdx* dodx, std::vector<uint8_t>& bytes) {
// Relatively large buffer as Kotlin metadata annotations may be huge.
constexpr size_t kRedZone = 1024;
constexpr size_t kBufferSize = 8192 - kRedZone;
uint8_t buffer[kBufferSize];
uint8_t* pend = buffer;
encode(dodx, pend);
always_assert_log((size_t)(pend - buffer) <= kBufferSize,
"DexEncodedValue::vencode overflow, size %d: %s",
(int)(pend - buffer), show().c_str());
for (uint8_t* p = buffer; p < pend; p++) {
bytes.push_back(*p);
}
}
void DexEncodedValueBit::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint8_t devtb = DEVT_HDR_TYPE(m_evtype);
if (m_val.m_value) {
devtb |= TO_DEVT_HDR_ARG(1);
}
*encdata++ = devtb;
}
void DexEncodedValueString::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint32_t sidx = dodx->stringidx(string());
type_encoder(encdata, m_evtype, sidx);
}
void DexEncodedValueType::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint32_t tidx = dodx->typeidx(type());
type_encoder(encdata, m_evtype, tidx);
}
void DexEncodedValueField::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint32_t fidx = dodx->fieldidx(field());
type_encoder(encdata, m_evtype, fidx);
}
void DexEncodedValueMethod::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint32_t midx = dodx->methodidx(method());
type_encoder(encdata, m_evtype, midx);
}
void DexEncodedValueMethodType::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint32_t pidx = dodx->protoidx(proto());
type_encoder(encdata, m_evtype, pidx);
}
void DexEncodedValueMethodHandle::encode(DexOutputIdx* dodx,
uint8_t*& encdata) {
uint32_t mhidx = dodx->methodhandleidx(methodhandle());
type_encoder(encdata, m_evtype, mhidx);
}
void DexEncodedValueArray::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
/*
* Static values are implied to be DEVT_ARRAY, and thus don't
* have a type byte.
*/
if (!m_static_val) {
uint8_t devtb = DEVT_HDR_TYPE(m_evtype);
*encdata++ = devtb;
}
encdata = write_uleb128(encdata, (uint32_t)evalues()->size());
for (auto const& ev : *evalues()) {
ev->encode(dodx, encdata);
}
}
void DexEncodedValueAnnotation::encode(DexOutputIdx* dodx, uint8_t*& encdata) {
uint8_t devtb = DEVT_HDR_TYPE(m_evtype);
uint32_t tidx = dodx->typeidx(m_type);
*encdata++ = devtb;
encdata = write_uleb128(encdata, tidx);
encdata = write_uleb128(encdata, (uint32_t)m_annotations.size());
for (auto const& dae : m_annotations) {
auto str = dae.string;
DexEncodedValue* dev = dae.encoded_value.get();
uint32_t sidx = dodx->stringidx(str);
encdata = write_uleb128(encdata, sidx);
dev->encode(dodx, encdata);
}
}
static DexAnnotationElement get_annotation_element(DexIdx* idx,
const uint8_t*& encdata) {
uint32_t sidx = read_uleb128(&encdata);
auto name = idx->get_stringidx(sidx);
always_assert_log(name != nullptr,
"Invalid string idx in annotation element");
return DexAnnotationElement(name,
DexEncodedValue::get_encoded_value(idx, encdata));
}
std::unique_ptr<DexEncodedValueArray> get_encoded_value_array(
DexIdx* idx, const uint8_t*& encdata) {
uint32_t size = read_uleb128(&encdata);
auto* evlist = new std::vector<std::unique_ptr<DexEncodedValue>>();
evlist->reserve(size);
for (uint32_t i = 0; i < size; i++) {
evlist->emplace_back(DexEncodedValue::get_encoded_value(idx, encdata));
}
return std::make_unique<DexEncodedValueArray>(evlist);
}
bool DexEncodedValue::is_evtype_primitive() const {
switch (m_evtype) {
case DEVT_BYTE:
case DEVT_SHORT:
case DEVT_CHAR:
case DEVT_INT:
case DEVT_LONG:
case DEVT_FLOAT:
case DEVT_DOUBLE:
// case DEVT_NULL:
case DEVT_BOOLEAN:
return true;
default:
return false;
};
}
bool DexEncodedValue::is_zero() const {
switch (m_evtype) {
case DEVT_BYTE:
case DEVT_SHORT:
case DEVT_CHAR:
case DEVT_INT:
case DEVT_LONG:
case DEVT_FLOAT:
case DEVT_DOUBLE:
case DEVT_BOOLEAN:
return m_val.m_value == 0;
case DEVT_NULL:
return true;
default:
return false;
}
}
bool DexEncodedValue::is_wide() const {
return m_evtype == DEVT_LONG || m_evtype == DEVT_DOUBLE;
}
std::unique_ptr<DexEncodedValue> DexEncodedValue::zero_for_type(DexType* type) {
if (type == type::_byte()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_BYTE, (uint64_t)0));
} else if (type == type::_char()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_CHAR, (uint64_t)0));
} else if (type == type::_short()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_SHORT, (uint64_t)0));
} else if (type == type::_int()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_INT, (uint64_t)0));
} else if (type == type::_long()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_LONG, (uint64_t)0));
} else if (type == type::_float()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_FLOAT, (uint64_t)0));
} else if (type == type::_double()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(DEVT_DOUBLE, (uint64_t)0));
} else if (type == type::_boolean()) {
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueBit(DEVT_BOOLEAN, false));
} else {
// not a primitive
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueBit(DEVT_NULL, false));
}
}
std::unique_ptr<DexEncodedValue> DexEncodedValue::get_encoded_value(
DexIdx* idx, const uint8_t*& encdata) {
uint8_t evhdr = *encdata++;
DexEncodedValueTypes evt = (DexEncodedValueTypes)DEVT_HDR_TYPE(evhdr);
uint8_t evarg = DEVT_HDR_ARG(evhdr);
switch (evt) {
case DEVT_SHORT:
case DEVT_INT:
case DEVT_LONG: {
uint64_t v = read_evarg(encdata, evarg, true /* sign_extend */);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(evt, v));
}
case DEVT_BYTE:
case DEVT_CHAR: {
uint64_t v = read_evarg(encdata, evarg, false /* sign_extend */);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(evt, v));
}
case DEVT_FLOAT: {
// We sign extend floats so that they can be treated just like signed ints
uint64_t v = read_evarg(encdata, evarg, true /* sign_extend */)
<< ((3 - evarg) * 8);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(evt, v));
}
case DEVT_DOUBLE: {
uint64_t v = read_evarg(encdata, evarg, false /* sign_extend */)
<< ((7 - evarg) * 8);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValuePrimitive(evt, v));
}
case DEVT_METHOD_TYPE: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
DexProto* evproto = idx->get_protoidx(evidx);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueMethodType(evproto));
}
case DEVT_METHOD_HANDLE: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
DexMethodHandle* evmethodhandle = idx->get_methodhandleidx(evidx);
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueMethodHandle(evmethodhandle));
}
case DEVT_NULL:
return std::unique_ptr<DexEncodedValue>(new DexEncodedValueBit(evt, false));
case DEVT_BOOLEAN:
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueBit(evt, evarg > 0));
case DEVT_STRING: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
auto evstring = idx->get_stringidx(evidx);
always_assert_log(evstring != nullptr,
"Invalid string idx in annotation element");
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueString(evstring));
}
case DEVT_TYPE: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
DexType* evtype = idx->get_typeidx(evidx);
always_assert_log(evtype != nullptr,
"Invalid type idx in annotation element");
return std::unique_ptr<DexEncodedValue>(new DexEncodedValueType(evtype));
}
case DEVT_FIELD:
case DEVT_ENUM: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
DexFieldRef* evfield = idx->get_fieldidx(evidx);
always_assert_log(evfield != nullptr,
"Invalid field idx in annotation element");
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueField(evt, evfield));
}
case DEVT_METHOD: {
uint32_t evidx = (uint32_t)read_evarg(encdata, evarg);
DexMethodRef* evmethod = idx->get_methodidx(evidx);
always_assert_log(evmethod != nullptr,
"Invalid method idx in annotation element");
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueMethod(evmethod));
}
case DEVT_ARRAY:
return get_encoded_value_array(idx, encdata);
case DEVT_ANNOTATION: {
EncodedAnnotations eanno{};
uint32_t tidx = read_uleb128(&encdata);
uint32_t count = read_uleb128(&encdata);
DexType* type = idx->get_typeidx(tidx);
always_assert_log(type != nullptr,
"Invalid DEVT_ANNOTATION within annotation type");
eanno.reserve(count);
for (uint32_t i = 0; i < count; i++) {
eanno.emplace_back(get_annotation_element(idx, encdata));
}
return std::unique_ptr<DexEncodedValue>(
new DexEncodedValueAnnotation(type, std::move(eanno)));
}
};
not_reached_log("Bogus annotation");
}
std::unique_ptr<DexAnnotation> DexAnnotation::get_annotation(
DexIdx* idx, uint32_t anno_off) {
if (anno_off == 0) return nullptr;
const uint8_t* encdata = idx->get_uleb_data(anno_off);
uint8_t viz = *encdata++;
always_assert_log(viz <= DAV_SYSTEM, "Invalid annotation visibility %d", viz);
uint32_t tidx = read_uleb128(&encdata);
uint32_t count = read_uleb128(&encdata);
DexType* type = idx->get_typeidx(tidx);
always_assert_log(type != nullptr, "Invalid annotation type");
auto anno =
std::make_unique<DexAnnotation>(type, (DexAnnotationVisibility)viz);
anno->m_anno_elems.reserve(count);
for (uint32_t i = 0; i < count; i++) {
anno->m_anno_elems.emplace_back(get_annotation_element(idx, encdata));
}
return anno;
}
void DexAnnotation::add_element(const char* key,
std::unique_ptr<DexEncodedValue> value) {
m_anno_elems.emplace_back(DexString::make_string(key), std::move(value));
}
void DexAnnotation::add_element(DexAnnotationElement elem) {
m_anno_elems.emplace_back(std::move(elem));
}
std::unique_ptr<DexAnnotationSet> DexAnnotationSet::get_annotation_set(
DexIdx* idx, uint32_t aset_off) {
if (aset_off == 0) return nullptr;
const uint32_t* adata = idx->get_uint_data(aset_off);
auto aset = std::make_unique<DexAnnotationSet>();
uint32_t count = *adata++;
aset->m_annotations.reserve(count - std::count(adata, adata + count, 0));
for (uint32_t i = 0; i < count; i++) {
uint32_t off = adata[i];
auto anno = DexAnnotation::get_annotation(idx, off);
if (anno != nullptr) {
aset->m_annotations.emplace_back(std::move(anno));
}
}
return aset;
}
void DexAnnotationDirectory::calc_internals() {
int cntviz = 0;
auto updateCount = [this](DexAnnotationSet* das) {
unsigned long ca, cv;
das->viz_counts(ca, cv);
m_anno_count += ca;
m_aset_size += 4 + 4 * (ca);
m_aset_count++;
return cv;
};
if (m_class) {
cntviz += updateCount(m_class);
}
if (m_field) {
for (auto const& p : *m_field) {
DexAnnotationSet* das = p.second;
cntviz += updateCount(das);
}
}
if (m_method) {
for (auto const& p : *m_method) {
DexAnnotationSet* das = p.second;
cntviz += updateCount(das);
}
}
if (m_method_param) {
for (auto const& p : *m_method_param) {
ParamAnnotations* pa = p.second;
m_xref_size += 4 + 4 * pa->size();
m_xref_count++;
for (auto const& pp : *pa) {
auto& das = pp.second;
cntviz += updateCount(das.get());
}
}
}
if (m_anno_count != 0) {
m_viz = (double)cntviz / m_anno_count;
}
}
bool method_annotation_compare(std::pair<DexMethod*, DexAnnotationSet*> a,
std::pair<DexMethod*, DexAnnotationSet*> b) {
return compare_dexmethods(a.first, b.first);
}
bool method_param_annotation_compare(
std::pair<DexMethod*, ParamAnnotations*> a,
std::pair<DexMethod*, ParamAnnotations*> b) {
return compare_dexmethods(a.first, b.first);
}
bool field_annotation_compare(std::pair<DexFieldRef*, DexAnnotationSet*> a,
std::pair<DexFieldRef*, DexAnnotationSet*> b) {
return compare_dexfields(a.first, b.first);
}
void DexAnnotationDirectory::gather_asets(
std::vector<DexAnnotationSet*>& aset) {
if (m_class) aset.push_back(m_class);
if (m_field) {
for (auto fanno : *m_field)
aset.push_back(fanno.second);
}
if (m_method) {
for (auto manno : *m_method)
aset.push_back(manno.second);
}
if (m_method_param) {
for (auto mpanno : *m_method_param) {
ParamAnnotations* params = mpanno.second;
for (auto& param : *params)
aset.push_back(param.second.get());
}
}
}
void DexAnnotationDirectory::gather_xrefs(
std::vector<ParamAnnotations*>& xrefs) {
if (m_method_param) {
std::sort(m_method_param->begin(),
m_method_param->end(),
method_param_annotation_compare);
for (auto param : *m_method_param) {
ParamAnnotations* pa = param.second;
xrefs.push_back(pa);
}
}
}
void DexAnnotationDirectory::gather_annotations(
std::vector<DexAnnotation*>& alist) {
if (m_class) m_class->gather_annotations(alist);
if (m_field) {
for (auto fanno : *m_field) {
DexAnnotationSet* das = fanno.second;
das->gather_annotations(alist);
}
}
if (m_method) {
for (auto manno : *m_method) {
DexAnnotationSet* das = manno.second;
das->gather_annotations(alist);
}
}
if (m_method_param) {
for (auto mpanno : *m_method_param) {
ParamAnnotations* params = mpanno.second;
for (auto& param : *params) {
auto& das = param.second;
das->gather_annotations(alist);
}
}
}
}
void DexAnnotationDirectory::vencode(
DexOutputIdx* dodx,
std::vector<uint32_t>& annodirout,
std::map<ParamAnnotations*, uint32_t>& xrefmap,
std::map<DexAnnotationSet*, uint32_t>& asetmap) {
uint32_t classoff = 0;
uint32_t cntaf = 0;
uint32_t cntam = 0;
uint32_t cntamp = 0;
if (m_class) {
always_assert_log(asetmap.count(m_class) != 0, "Uninitialized aset %p '%s'",
m_class, show(m_class).c_str());
classoff = asetmap[m_class];
}
if (m_field) {
cntaf = (uint32_t)m_field->size();
}
if (m_method) {
cntam = (uint32_t)m_method->size();
}
if (m_method_param) {
cntamp = (uint32_t)m_method_param->size();
}
annodirout.push_back(classoff);
annodirout.push_back(cntaf);
annodirout.push_back(cntam);
annodirout.push_back(cntamp);
if (m_field) {
/* Optimization note:
* A tape sort could be used instead as there are two different
* ordered lists here.
*/
std::sort(m_field->begin(), m_field->end(), field_annotation_compare);
for (auto const& p : *m_field) {
DexAnnotationSet* das = p.second;
annodirout.push_back(dodx->fieldidx(p.first));
always_assert_log(asetmap.count(das) != 0, "Uninitialized aset %p '%s'",
das, show(das).c_str());
annodirout.push_back(asetmap[das]);
}
}
if (m_method) {
std::sort(m_method->begin(), m_method->end(), method_annotation_compare);
for (auto const& p : *m_method) {
DexMethod* m = p.first;
DexAnnotationSet* das = p.second;
uint32_t midx = dodx->methodidx(m);
annodirout.push_back(midx);
always_assert_log(asetmap.count(das) != 0, "Uninitialized aset %p '%s'",
das, show(das).c_str());
annodirout.push_back(asetmap[das]);
}
}
if (m_method_param) {
std::sort(m_method_param->begin(),
m_method_param->end(),
method_param_annotation_compare);
for (auto const& p : *m_method_param) {
ParamAnnotations* pa = p.second;
annodirout.push_back(dodx->methodidx(p.first));
always_assert_log(xrefmap.count(pa) != 0,
"Uninitialized ParamAnnotations %p", pa);
annodirout.push_back(xrefmap[pa]);
}
}
}
void DexAnnotationSet::gather_annotations(std::vector<DexAnnotation*>& list) {
for (auto& annotation : m_annotations) {
list.push_back(annotation.get());
}
}
void DexAnnotationSet::vencode(DexOutputIdx* dodx,
std::vector<uint32_t>& asetout,
std::map<DexAnnotation*, uint32_t>& annoout) {
asetout.push_back((uint32_t)m_annotations.size());
std::sort(m_annotations.begin(), m_annotations.end(),
[](const auto& a, const auto& b) {
return compare_dextypes(a->type(), b->type());
});
for (auto& anno : m_annotations) {
always_assert_log(annoout.count(anno.get()) != 0,
"Uninitialized annotation %p '%s', bailing\n",
anno.get(),
show(anno.get()).c_str());
asetout.push_back(annoout[anno.get()]);
}
}
static void uleb_append(std::vector<uint8_t>& bytes, uint32_t v) {
uint8_t tarray[5];
uint8_t* pend = write_uleb128(tarray, v);
for (uint8_t* p = tarray; p < pend; p++) {
bytes.push_back(*p);
}
}
void DexAnnotation::vencode(DexOutputIdx* dodx, std::vector<uint8_t>& bytes) {
bytes.push_back(m_viz);
uleb_append(bytes, dodx->typeidx(m_type));
uleb_append(bytes, (uint32_t)m_anno_elems.size());
for (auto& elem : m_anno_elems) {
auto string = elem.string;
DexEncodedValue* ev = elem.encoded_value.get();
uleb_append(bytes, dodx->stringidx(string));
ev->vencode(dodx, bytes);
}
}
namespace {
std::string show_helper(const DexEncodedValueArray* a, bool deobfuscated) {
std::ostringstream ss;
ss << (a->is_static_val() ? "(static) " : "");
if (a->evalues()) {
bool first = true;
for (const auto& evalue : *a->evalues()) {
if (!first) {
ss << ' ';
}
if (deobfuscated) {
ss << evalue->show_deobfuscated();
} else {
ss << evalue->show();
}
first = false;
}
}
return ss.str();
}
std::string show_helper(const EncodedAnnotations* annos, bool deobfuscated) {
if (!annos) {
return "";
}
std::ostringstream ss;
bool first = true;
for (auto const& pair : *annos) {
if (!first) {
ss << ", ";
}
ss << show(pair.string) << ":";
if (deobfuscated) {
ss << pair.encoded_value->show_deobfuscated();
} else {
ss << pair.encoded_value->show();
}
first = false;
}
return ss.str();
}
} // namespace
std::string show(const EncodedAnnotations* annos) {
return show_helper(annos, false);
}
std::string show_deobfuscated(const EncodedAnnotations* annos) {
return show_helper(annos, true);
}
std::string show(const EncodedAnnotations& annos) {
return show_helper(&annos, false);
}
std::string show_deobfuscated(const EncodedAnnotations& annos) {
return show_helper(&annos, true);
}
std::string DexEncodedValue::show() const {
std::ostringstream ss;
ss << as_value();
return ss.str();
}
std::string DexEncodedValueAnnotation::show() const {
std::ostringstream ss;
ss << "type:" << ::show(m_type) << " annotations:" << ::show(m_annotations);
return ss.str();
}
std::string DexEncodedValueAnnotation::show_deobfuscated() const {
std::ostringstream ss;
ss << "type:" << ::show(m_type)
<< " annotations:" << ::show_deobfuscated(m_annotations);
return ss.str();
}
std::string DexEncodedValueArray::show() const {
return show_helper(this, false);
}
std::string DexEncodedValueArray::show_deobfuscated() const {
return show_helper(this, true);
}
std::string DexEncodedValueString::show() const { return ::show(string()); }
std::string DexEncodedValueType::show() const { return ::show(type()); }
std::string DexEncodedValueField::show() const { return ::show(field()); }
std::string DexEncodedValueField::show_deobfuscated() const {
return ::show_deobfuscated(field());
}
std::string DexEncodedValueMethod::show() const { return ::show(method()); }
std::string DexEncodedValueMethod::show_deobfuscated() const {
return ::show_deobfuscated(method());
}
std::string DexEncodedValueMethodType::show() const { return ::show(proto()); }
std::string DexEncodedValueMethodType::show_deobfuscated() const {
return ::show_deobfuscated(proto());
}
std::string DexEncodedValueMethodHandle::show() const {
return ::show(methodhandle());
}
std::string DexEncodedValueMethodHandle::show_deobfuscated() const {
// TODO(T58570881) - fix deobfuscation
return ::show(methodhandle());
}