@@ -5791,6 +5791,142 @@ R_API void r_core_anal_propagate_noreturn(RCore *core, ut64 addr) {
57915791 r_bitset_free (done );
57925792}
57935793
5794+ // a -fPIC object calls its own globals through the plt; flag those stubs so
5795+ // calls read sym.plt.<target> instead of an anonymous fcn address
5796+ static void plt_stub_flag (RCore * core , ut64 entry , ut64 size , ut64 slot ) {
5797+ const int ptrsz = R_MAX (4 , core -> anal -> config -> bits / 8 );
5798+ // the reloc tree keeps file vaddrs while the decoded slot is a runtime address
5799+ RBinObject * bo = r_bin_cur_object (core -> bin );
5800+ const st64 shift = bo ? bo -> baddr_shift : 0 ;
5801+ RBinReloc * rel = r_core_getreloc (core , slot - shift , ptrsz );
5802+ if (!rel || rel -> import || !rel -> symbol ) {
5803+ return ;
5804+ }
5805+ RBinSymbol * target = rel -> symbol ;
5806+ if (!target -> vaddr || target -> vaddr == UT64_MAX || target -> vaddr == entry ) {
5807+ return ;
5808+ }
5809+ // STT_GNU_IFUNC is the only type r2 maps to LOOS
5810+ if (!target -> type || (strcmp (target -> type , R_BIN_TYPE_FUNC_STR )
5811+ && strcmp (target -> type , R_BIN_TYPE_LOOS_STR ))) {
5812+ return ;
5813+ }
5814+ const char * tname = r_bin_name_tostring2 (target -> name , 'o' );
5815+ if (R_STR_ISEMPTY (tname )) {
5816+ return ;
5817+ }
5818+ char * fname = r_str_newf ("sym.plt.%s" , tname );
5819+ r_name_filter (fname , -1 );
5820+ if (!r_flag_get (core -> flags , fname )) {
5821+ r_flag_set (core -> flags , fname , entry , size );
5822+ }
5823+ free (fname );
5824+ }
5825+
5826+ // walk the section decoding entries: remember the last lea and load, and when an
5827+ // entry ends in an indirect jump derive the got slot it goes through
5828+ static void plt_stub_scan_section (RCore * core , RBinSection * sec ) {
5829+ if (sec -> vsize < 8 || sec -> vsize > 0x100000 ) {
5830+ return ;
5831+ }
5832+ const ut64 sec_vaddr = r_bin_get_vaddr (core -> bin , sec -> paddr , sec -> vaddr );
5833+ const int len = (int )sec -> vsize ;
5834+ ut8 * buf = malloc (len );
5835+ if (!buf || !r_io_read_at (core -> io , sec_vaddr , buf , len )) {
5836+ free (buf );
5837+ return ;
5838+ }
5839+ const int minop = R_MAX (1 , r_arch_info (core -> anal -> arch , R_ARCH_INFO_MINOP_SIZE ));
5840+ ut64 entry = sec_vaddr ;
5841+ ut64 lea_ptr = UT64_MAX ;
5842+ ut64 load_disp = UT64_MAX ;
5843+ int i = 0 ;
5844+ while (i < len ) {
5845+ const ut64 at = sec_vaddr + i ;
5846+ RAnalOp op ;
5847+ const int oplen = r_anal_op (core -> anal , & op , at , buf + i , len - i , R_ARCH_OP_MASK_BASIC );
5848+ const int type = op .type & R_ANAL_OP_TYPE_MASK & ~R_ANAL_OP_TYPE_COND ;
5849+ const bool indirect = type == R_ANAL_OP_TYPE_UJMP
5850+ || (type == R_ANAL_OP_TYPE_JMP && (op .type & R_ANAL_OP_TYPE_MEM ));
5851+ bool ends = true;
5852+ if (oplen < 1 ) {
5853+ r_anal_op_fini (& op );
5854+ i += minop ;
5855+ entry = sec_vaddr + i ;
5856+ lea_ptr = UT64_MAX ;
5857+ load_disp = UT64_MAX ;
5858+ continue ;
5859+ }
5860+ if (indirect ) {
5861+ // x86 encodes the slot in one op; arm64-alikes split it lea/load/branch
5862+ ut64 slot = (op .ptr > 0 && op .ptr != -1 )? (ut64 )op .ptr : UT64_MAX ;
5863+ if (slot == UT64_MAX && lea_ptr != UT64_MAX && load_disp != UT64_MAX ) {
5864+ slot = lea_ptr + load_disp ;
5865+ }
5866+ if (slot != UT64_MAX ) {
5867+ plt_stub_flag (core , entry , at + oplen - entry , slot );
5868+ }
5869+ } else {
5870+ switch (type ) {
5871+ case R_ANAL_OP_TYPE_LEA :
5872+ case R_ANAL_OP_TYPE_MOV :
5873+ if (op .ptr > 0 && op .ptr != -1 ) {
5874+ lea_ptr = (ut64 )op .ptr ;
5875+ }
5876+ ends = false;
5877+ break ;
5878+ case R_ANAL_OP_TYPE_LOAD :
5879+ if (op .ptr > 0 && op .ptr != -1 ) {
5880+ // riscv-style loads resolve the slot in the op itself
5881+ lea_ptr = (ut64 )op .ptr ;
5882+ load_disp = 0 ;
5883+ } else {
5884+ load_disp = op .disp ;
5885+ }
5886+ ends = false;
5887+ break ;
5888+ case R_ANAL_OP_TYPE_JMP :
5889+ case R_ANAL_OP_TYPE_CALL :
5890+ case R_ANAL_OP_TYPE_UCALL :
5891+ case R_ANAL_OP_TYPE_RET :
5892+ case R_ANAL_OP_TYPE_TRAP :
5893+ case R_ANAL_OP_TYPE_SWI :
5894+ case R_ANAL_OP_TYPE_ILL :
5895+ case R_ANAL_OP_TYPE_UNK :
5896+ case R_ANAL_OP_TYPE_NOP : // trailing padding belongs to no entry
5897+ break ;
5898+ default :
5899+ ends = false;
5900+ break ;
5901+ }
5902+ }
5903+ r_anal_op_fini (& op );
5904+ i += oplen ;
5905+ if (ends ) {
5906+ entry = sec_vaddr + i ;
5907+ lea_ptr = UT64_MAX ;
5908+ load_disp = UT64_MAX ;
5909+ }
5910+ }
5911+ free (buf );
5912+ }
5913+
5914+ R_API void r_core_anal_plt_stubs (RCore * core ) {
5915+ R_RETURN_IF_FAIL (core );
5916+ RVecRBinSection * sections = r_bin_get_sections_vec (core -> bin );
5917+ if (!sections ) {
5918+ return ;
5919+ }
5920+ r_flag_space_push (core -> flags , R_FLAGS_FS_SYMBOLS );
5921+ RBinSection * sec ;
5922+ R_VEC_FOREACH (sections , sec ) {
5923+ if (sec -> name && strstr (sec -> name , "plt" ) && (sec -> perm & R_PERM_X )) {
5924+ plt_stub_scan_section (core , sec );
5925+ }
5926+ }
5927+ r_flag_space_pop (core -> flags );
5928+ }
5929+
57945930R_API char * r_core_anal_get_comments (RCore * core , ut64 addr ) {
57955931 if (core ) {
57965932 const char * type = r_meta_get_string (core -> anal , R_META_TYPE_VARTYPE , addr );
0 commit comments