GDB中打印ART基础类
【art::mirror::String】
(gdb) p /x *('art::mirror::String' *)0x71237d00 $89 = { ... count_ = 0x11, hash_code_ = 0x6c3617af, value_ = 0x71237d10, ... }
其中count_是字符串长度,value_是字符串buffer,buffeer里的内容是Unicode字符串:
(gdb) x /17hc 0x71237d10 0x71237d10: 97 'a' 110 'n' 100 'd' 114 'r' 111 'o' 105 'i' 100 'd' 46 '.' 0x71237d20: 118 'v' 105 'i' 101 'e' 119 'w' 46 '.' 86 'V' 105 'i' 101 'e' 0x71237d30: 119 'w'
因此,这个String类对象是"android.view.View"
对应脚本及用法如下:
define art_print_string
set $local_string = ('art::mirror::String' *) $arg0
set $string_length = (int) $local_string->count_
set $declaringstr = (char*)($local_string->value_)
set $logcal_index = (int) 0
set $string_length = (int) 2*$string_length
while $logcal_index < $string_length
printf "%c", *($declaringstr + $logcal_index)
set $logcal_index = $logcal_index + 2
end
end
(gdb) art_print_string 0x71237d00
android.view.View
【art::mirror::Class】
(gdb) p /x *('art::mirror::Class' *)0x70eac5e0 $90 = { ... dex_cache_ = { <art::mirror::ObjectReference<false, art::mirror::DexCache>> = { reference_ = 0x70dac310 }, <No data fields>}, ...
name_ = { <art::mirror::ObjectReference<false, art::mirror::String>> = { reference_ = 0x71237d00 }, <No data fields>}, ... dex_type_idx_ = 0x61f, ... } }
这里分两种,如果类被Resolve过,则就可以直接通过art::mirror::String类的name_字段获取类名
否则就得从dex_file_中读取,而dex_file_的地址保存在dex_cache_中:
(gdb) p /x *('art::mirror::DexCache' *)0x70dac310
$97 = {
...
dex_file_ = 0x7f9ba7b780,
resolved_fields_ = 0x71a80078,
resolved_methods_ = 0x719c8b78,
...
}
dex_file_的结构如下:
(gdb) p /x *('art::DexFile' *)0x7f9ba7b280 $98 = { begin_ = 0x72ffa3cc, size_ = 0x7fdf88, ... header_ = 0x72ffa3cc, string_ids_ = 0x72ffa43c, type_ids_ = 0x73046ab4, field_ids_ = 0x7306afe0, method_ids_ = 0x730b24c8, proto_ids_ = 0x7304c7a0, class_defs_ = 0x7311d350, oat_dex_file_ = 0x7f9ba2f200, ... }
根据dex_file_中的type_ids_指针和class中的dex_type_idx_,找到该类的TypeId
(gdb) p /x *(('art::DexFile::TypeId' *)0x73046ab4+0x61f)
$101 = {
descriptor_idx_ = 0x3741
}
这个descriptor_idx_就是类名字符串的StringId在string_ids_中的偏移:
(gdb) p *(('art::DexFile::StringId' *)0x72ffa43c+0x3741)
$102 = {
string_data_off_ = 0x52f79d
}
最终得到的string_data_off_就是类名字符串真正存放的地址:dex_file_(base = 0x73ffa3cc)中的相对偏移。
因此,最终的字符串的地址是:
(gdb) p /x 0x72ffa3cc+0x52f79d
$103 = 0x73529b69
这个地址存放的是Leb128类型的字符串,对于长度小于128的字符串,它的长度放在buffer的第一个位置,后面存放的就是字符串的ASCII码:
(gdb) x /b 0x73529b69 0x73529b69: 0x13
(gdb) x /s 0x73529b69+1 0x73529b6a: "Landroid/view/View;"
对应脚本及用法如下:
define art_print_class
set $myclass = ('art::mirror::Class' *)$arg0
set $classstring = ('art::mirror::String' *)($myclass->name_.reference_)
if $classstring != 0
art_print_string $classstring
else
set $dexfile = ('art::DexFile' *) (('art::mirror::DexCache' *)$myclass->dex_cache_.reference_)->dex_file_
set $dextypeidx = (int) $myclass->dex_type_idx_
set $descriptoridx = (int) ($dexfile->type_ids_ + $dextypeidx)->descriptor_idx_
set $classnameptr = (char*) ($dexfile->string_ids_[$descriptoridx].string_data_off_ + $dexfile->begin_ + 1)
art_print_cstring $classnameptr
end
end
define art_print_cstring
set $buffer = (char*)$arg0
if *$buffer == 'L'
set $buffer = $buffer + 1
while *$buffer != ';'
if *$buffer == 0
loop_break
end
if *$buffer == '\/'
printf "."
else
printf "%c", *$buffer
end
set $buffer = $buffer + 1
end
else
printf "%s", $buffer
end
end
(gdb) art_print_class 0x70eac5e0
android.view.View
【art::mirror::Object】
(gdb) p /x *('art::mirror::Object' *)0x1354a5e0
$114 = {
static kVTableLength = 0xb,
static hash_code_seed = {
<std::__1::atomic<unsigned int>> = {
<std::__1::__atomic_base<unsigned int, true>> = {
<std::__1::__atomic_base<unsigned int, false>> = {
__a_ = 0xf2e119b1
}, <No data fields>}, <No data fields>}, <No data fields>},
klass_ = {
<art::mirror::ObjectReference<false, art::mirror::Class>> = {
reference_ = 0x70eac5e0
}, <No data fields>},
monitor_ = 0x0
}
对于Object来说,只需要打印所属类名就可以了。
对应脚本及用法如下:
define art_print_object
set $curclass = ('art::mirror::Class' *)((('art::mirror::Object' *)$arg0)->klass_.reference_)
art_printn_class $curclass
end
(gdb) art_print_object 0x1354a5e0
android.view.View
【art::ArtMethod】
(gdb) p /x *('art::ArtMethod' *)0x7144b280 $115 = { declaring_class_ = { root_ = { <art::mirror::ObjectReference<false, art::mirror::Object>> = { reference_ = 0x70eac5e0 }, <No data fields>} }, access_flags_ = 0x90001, dex_code_item_offset_ = 0x1d5968, dex_method_index_ = 0x307a, method_index_ = 0xa, hotness_count_ = 0x0, ptr_sized_fields_ = { dex_cache_resolved_methods_ = 0x719c8b7800000000, dex_cache_resolved_types_ = 0x719c2e8800000000, entry_point_from_jni_ = 0x0, entry_point_from_quick_compiled_code_ = 0x75f568b400000000 } }
打印方法名分三部分:
1、方法所属类
2、方法名
3、参数及返回值
方法所属类这个可以简单的打印ArtMethod的declaring_class_即可
(gdb) art_print_class 0x70eac5e0 android.view.View
可以通过declaring_class_找到DexCache,进而找到DexFile。
通过ArtMethod中的dex_method_index和DexFile中的method_ids_,找到该方法对应的MethodId:
(gdb) p /x *('art::DexFile' *)0x7f9ba7b280 $98 = { begin_ = 0x72ffa3cc, size_ = 0x7fdf88, ... header_ = 0x72ffa3cc, string_ids_ = 0x72ffa43c, type_ids_ = 0x73046ab4, field_ids_ = 0x7306afe0, method_ids_ = 0x730b24c8, proto_ids_ = 0x7304c7a0, class_defs_ = 0x7311d350, oat_dex_file_ = 0x7f9ba2f200, ... } (gdb) p /x *(('art::DexFile::MethodId' *)0x730b24c8+0x307a) $117 = { class_idx_ = 0x61f, proto_idx_ = 0x155e, name_idx_ = 0x9f2 }
其中MethodId中的
class_idx_是方法所属类的TypeId的索引值,通过前面的分析可知,0x61f对应的就是android.view.View。
proto_idx_是方法原型的索引,通过这个索引可在DexFile中的proto_ids_中查找该方法对应的原型。
name_idx_是方法名在字符串池中的偏移。
先看看方法名:
(gdb) x /8c (('art::DexFile::StringId' *)0x72ffa43c+0x9f2).string_data_off_ + 0x72ffa3cc 0x734e212c: 6 '\006' 60 '<' 105 'i' 110 'n' 105 'i' 116 't' 62 '>' 0 '\000'
方法名是长度为6的字符串"<init>",也就是android.view.View类的构造函数。
再看看方法的原型:
(gdb) p /x *(('art::DexFile::ProtoId' *)0x7304c7a0+0x155e) $120 = { shorty_idx_ = 0x764b, return_type_idx_ = 0x1588, pad_ = 0x0, parameters_off_ = 0x4c51b4 }
return_type_idx_是方法的返回值在DexFile的TypeId(0x73046ab4)数组里的偏移。
(gdb) p /x *(('art::DexFile::TypeId' *)0x73046ab4+0x1588) $121 = { descriptor_idx_ = 0x745a } (gdb) x /8c (('art::DexFile::StringId' *)0x72ffa43c+0x745a).string_data_off_ + 0x72ffa3cc 0x735a4fb9: 1 '\001' 86 'V' 0 '\000' 16 '\020' 86 'V' 49 '1' 95 '_' 80 'P'
返回值类型是长度为1的字符串"V"
parameters_off_(0x4c51b4)是参数列表距dexfile起始位置(0x72ffa3cc)的的偏移:
(gdb) p /x * ('art::DexFile::TypeList' *)(0x72ffa3cc+0x4c51b4) $122 = { size_ = 0x3, list_ = {{ type_idx_ = 0x9b }} }
该函数有3个参数,每个参数的在TypeId中的偏移为:
(gdb) p /x (('art::DexFile::TypeList' *)(0x72ffa3cc+0x4c51b4))->list_[0] $124 = { type_idx_ = 0x9b } (gdb) p /x (('art::DexFile::TypeList' *)(0x72ffa3cc+0x4c51b4))->list_[1] $125 = { type_idx_ = 0x48a } (gdb) p /x (('art::DexFile::TypeList' *)(0x72ffa3cc+0x4c51b4))->list_[2] $126 = { type_idx_ = 0x4 }
三个参数descriptor_idx_及字符串为:
(gdb) p /x (('art::DexFile::TypeId' *)0x73046ab4+0x9b).descriptor_idx_ $130 = 0x3149 (gdb) p /x (('art::DexFile::TypeId' *)0x73046ab4+0x48a).descriptor_idx_ $131 = 0x356d (gdb) p /x (('art::DexFile::TypeId' *)0x73046ab4+0x4).descriptor_idx_ $132 = 0x27cc (gdb) x /26c (('art::DexFile::StringId' *)0x72ffa43c+0x3149).string_data_off_ + 0x72ffa3cc 0x7351ac73: 25 '\031' 76 'L' 97 'a' 110 'n' 100 'd' 114 'r' 111 'o' 105 'i' 0x7351ac7b: 100 'd' 47 '/' 99 'c' 111 'o' 110 'n' 116 't' 101 'e' 110 'n' 0x7351ac83: 116 't' 47 '/' 67 'C' 111 'o' 110 'n' 116 't' 101 'e' 120 'x' 0x7351ac8b: 116 't' 59 ';' (gdb) x /28c (('art::DexFile::StringId' *)0x72ffa43c+0x356d).string_data_off_ + 0x72ffa3cc 0x735253f4: 27 '\033' 76 'L' 97 'a' 110 'n' 100 'd' 114 'r' 111 'o' 105 'i' 0x735253fc: 100 'd' 47 '/' 117 'u' 116 't' 105 'i' 108 'l' 47 '/' 65 'A' 0x73525404: 116 't' 116 't' 114 'r' 105 'i' 98 'b' 117 'u' 116 't' 101 'e' 0x7352540c: 83 'S' 101 'e' 116 't' 59 ';' (gdb) x /2c (('art::DexFile::StringId' *)0x72ffa43c+0x27cc).string_data_off_ + 0x72ffa3cc 0x7350ed6e: 1 '\001' 73 'I'
分别是
长度为25的"Landroid/context/Context;"
长度为27的"Landroid/util/AttributeSet;"
长度为1的"I"
将上诉内容用脚本实现:
define art_get_method_name_by_method_id set $methodid = ('art::ArtMethod' *)$arg0 set $declaringclass = ('art::mirror::Class' *) $methodid->declaring_class_.root_.reference_ set $dexfile = ('art::DexFile' *) (('art::mirror::DexCache' *) $declaringclass->dex_cache_.reference_)->dex_file_ art_print_class $declaringclass set $methodidx = (int) $methodid->dex_method_index_ set $methodnameidx = (int) $dexfile->method_ids_[$methodidx]->name_idx_ set $methodstr = (char*) ($dexfile->string_ids_[$methodnameidx].string_data_off_ + $dexfile->begin_ + 1) printf ".%s ", $methodstr set $protoid = ('art::DexFile::ProtoId' *)$dexfile->proto_ids_ + $dexfile->method_ids_[$methodidx]->proto_idx_ printf "\"(" if $protoid->parameters_off_ != 0 set $typelist = ('art::DexFile::TypeList' *)($dexfile->begin_ + $protoid->parameters_off_) set $typelistsize = (int)$typelist->size_ set $typelistitems = (unsigned short *) ($typelist->list_) set $logcal_index = (int) 0 while $logcal_index < $typelistsize set $descriptoridx = (int) ($dexfile->type_ids_ + *($typelistitems +$logcal_index))->descriptor_idx_ set $paramstr = (char*) ($dexfile->string_ids_[$descriptoridx].string_data_off_ + $dexfile->begin_ + 1) printf "%s", $paramstr set $logcal_index = $logcal_index + 1 end end printf ")" set $descriptoridx = (int) ($dexfile->type_ids_ + $protoid->return_type_idx_)->descriptor_idx_ set $returnstr = (char*) ($dexfile->string_ids_[$descriptoridx].string_data_off_ + $dexfile->begin_ + 1) printf "%s\"\n", $returnstr end
用法如下:
(gdb) art_get_method_name_by_method_id 0x7144b280
android.view.View.<init> "(Landroid/content/Context;Landroid/util/AttributeSet;I)V"