【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 ' 06' 60 '<' 105 'i' 110 'n' 105 'i' 116 't' 62 '>' 0 ' 00'
方法名是长度为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 ' 01' 86 'V' 0 ' 00' 16 ' 20' 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 ' 31' 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 ' 33' 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 ' 01' 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"
", $returnstr
end
用法如下:
(gdb) art_get_method_name_by_method_id 0x7144b280
android.view.View.<init> "(Landroid/content/Context;Landroid/util/AttributeSet;I)V"