zoukankan      html  css  js  c++  java
  • 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 '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"
  • 相关阅读:
    C# 并行线程调用
    Oracle定时备份
    读取Excel里面的内容转为DataTable
    c# 将json数据转为键值对
    Py基础+中级
    深入理解DIP、IoC、DI以及IoC容器(转载)
    错误页面的配置
    JavaScript重载
    关于为空必填js判断
    MyEclipse CI 2018.8.0正式发布(附下载)
  • 原文地址:https://www.cnblogs.com/YYPapa/p/6858787.html
Copyright © 2011-2022 走看看