OSDN Git Service

ce851fd8203128854231a84875cf8b7625b4c680
[drdeamon64/drdeamon64.git] / libgoblin / drd64_libgoblin_elf_dynsym.c
1 /*DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64
2
3                          D r . D e a m o n  6 4
4                         for INTEL64(R), AMD64(R)
5         
6    Copyright(C) 2007-2009 Koine Yuusuke(koinec). All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10
11  1. Redistributions of source code must retain the above copyright notice,
12     this list of conditions and the following disclaimer.
13  2. Redistributions in binary form must reproduce the above copyright
14     notice, this list of conditions and the following disclaimer in the
15     documentation and/or other materials provided with the distribution.
16
17 THIS SOFTWARE IS PROVIDED BY Koine Yuusuke(koinec) ``AS IS'' AND ANY
18 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL Koine Yuusuke(koinec) OR CONTRIBUTORS BE
21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27 OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64DrDeAmOn64*/
30
31 /* File Info -----------------------------------------------------------
32 File: drd64_.c
33 Function: 
34 Comment: 
35 ----------------------------------------------------------------------*/
36
37 #define DRD64_SRC_LIBGOBLIN_ELF_DYNSYM
38 #include"drd64_libgoblin.h"
39
40
41 /*----------------------------------------------------------------------
42 ----------------------------------------------------------------------*/
43 int
44         ELF_DynSym_ReSetPLTsize_inObjectInfo(
45                         LibGoblin_ProgramInfo *p_pginfo,
46                         LibGoblin_BinaryInfo *p_binfo )
47 {
48         QWord                                   qw_size;
49         LibGoblin_SectionInfo   *psec_plt;
50         LibGoblin_ObjectInfo    *pobj_plt;
51         LibGoblin_ObjectInfo    *pobj_now;
52         LibGoblin_ObjectInfo    *pobj_next;
53
54         psec_plt        = Section_GetSectionInfo( p_binfo, LIBGOBLIN_SECTION_ID_PLT );
55         assert( NULL != psec_plt );
56         if( NULL == psec_plt->pb_data ) {
57                 return 0x00;
58         }
59
60         pobj_plt        = ObjectInfo_GetObjectInfo( p_pginfo, psec_plt->i_objid );
61         assert( NULL != pobj_plt );
62
63         pobj_now        = ObjectInfo_GetGroupChildTop( p_pginfo, pobj_plt );
64         while( NULL != pobj_now )       {
65                 pobj_next       = ObjectInfo_GetGroupNext( p_pginfo, pobj_now );
66
67                 if( 0 == pobj_now->addr.qw_size )       {
68                         if( NULL != pobj_next )         {
69                                 qw_size = pobj_next->addr.ptr_addr.value - pobj_now->addr.ptr_addr.value;
70                         }
71                         else    {
72                                 qw_size = (pobj_plt->addr.ptr_addr.value + pobj_plt->addr.qw_size)
73                                                                 - pobj_now->addr.ptr_addr.value;
74                         }
75                         pobj_now->addr.qw_size  = qw_size;
76                 }
77
78                 pobj_now        = pobj_next;
79         }
80
81         return 0x00;
82 }
83
84
85 /*----------------------------------------------------------------------
86 ----------------------------------------------------------------------*/
87 LIBGOBLIN_ELF_DYNSYM_EXTERN
88 int
89         ELF64_DynSym_ReadSection(
90                         LibGoblin_BinaryInfo    *p_binfo )
91 {
92         char    *pstr_symname;
93         Byte    b_binding;
94         Byte    b_bindtemp;
95         Byte    *pb_dynstr;
96         int             i_bid;
97         int             i_result;
98         int             i_symindex;
99         Word    w_gnuver        = 0;
100         Word    *pw_gnuver      = NULL;
101         DWord   dw_cnt;
102         DWord   dw_sym;
103         DWord   dw_vermax;
104         DWord   dw_symbols;
105         DWord   dw_status;
106         QWord   qw_size;
107         Elf64_Shdr      *p_shdr;
108         Elf64_Sym       *p_sym;
109         PtrValue        ptr_addr;
110         GnuVer_VerNeed  *p_verneed;
111         GnuVer_VerNeed  *p_vernow;
112         LibGoblin_SectionInfo   *psec_gnuver    = NULL;
113         LibGoblin_SectionInfo   *psec_dynsym;
114         LibGoblin_SectionInfo   *psec_dynstr;
115         LibGoblin_SectionInfo   *psec_plt;
116         LibGoblin_ObjectInfo    *p_obj;
117         LibGoblin_ProgramInfo   *p_pginfo;
118         LibGoblin_BinaryInfo    *p_binlib;
119
120         // Check exist .dynsym section ---
121         psec_dynsym     = Section_GetSectionInfo(
122                                                         p_binfo, LIBGOBLIN_SECTION_ID_DYNSYM );
123         assert( NULL != psec_dynsym );
124         if( NULL == psec_dynsym->pb_sechdr )    {
125                 return 0x00;
126         }
127         p_shdr  = (Elf64_Shdr *)(psec_dynsym->pb_sechdr);
128
129         // Check exist .dynstr section ---
130         psec_dynstr     = Section_GetSectionInfo(
131                                                         p_binfo, LIBGOBLIN_SECTION_ID_DYNSTR );
132         assert( NULL != psec_dynstr );
133         if( NULL == psec_dynstr->pb_data )      {
134                 return 0x00;
135         }
136         pb_dynstr       = psec_dynstr->pb_data;
137
138         // Check exist .plt section ---
139         psec_plt        = Section_GetSectionInfo( p_binfo, LIBGOBLIN_SECTION_ID_PLT );
140         assert( NULL != psec_plt );
141         if( NULL == psec_plt->pb_data ) {
142                 return 0x00;
143         }
144
145         // Read & Generate DynSym_Version struct data ---
146         p_verneed       = ELF64_GnuVer_GenerateGnuVerNeed( &dw_vermax, p_binfo );
147         if( NULL != p_verneed ) {
148                 psec_gnuver     = Section_GetSectionInfo(
149                                                                 p_binfo, LIBGOBLIN_SECTION_ID_GNU_VERSION );
150                 assert( NULL != psec_gnuver );
151                 if( NULL == psec_gnuver->pb_data )      {
152                         return 0x00;
153                 }
154                 pw_gnuver       = (Word *)psec_gnuver->pb_data;
155         }
156
157         dw_symbols      = (DWord)p_shdr->sh_size / (DWord)p_shdr->sh_entsize;
158
159         // Read .dymsym & .gnu.version for ObjectInfo
160         p_pginfo        = ProgInfo_GetProgInfo( p_binfo->i_pginfo );
161         assert( NULL != p_pginfo );
162
163         // Loop. ---
164         p_sym   = (Elf64_Sym *)psec_dynsym->pb_data;
165         for( dw_sym = 0; dw_sym < dw_symbols; dw_sym++, p_sym++ )       {
166                 if( NULL != pw_gnuver ) { w_gnuver      = (*pw_gnuver++) & 0x7fff; }
167                 
168                 // NODATA symbol.
169                 if(( 0x00000000 == p_sym->st_value )
170                                 && ( STT_NOTYPE == ELF64_ST_TYPE( p_sym->st_info ) ))
171                         { continue; }
172
173                 // Source file. -- XXX: WARNING!!
174                 if( STT_FILE == ELF64_ST_TYPE( p_sym->st_info ) )       {
175                         // XXX - WARNING Msg.
176                         continue;
177                 }
178
179                 // If p_sym->st_shndx != 0(UNDEF),
180                 //   the symbol object is implemented in self-object.
181                 //if( SHN_UNDEF != p_sym->st_shndx )    { continue; }
182                 if( SHN_UNDEF != p_sym->st_shndx )      {
183                         ptr_addr                = (PtrValue)p_sym->st_value;
184                         qw_size                 = p_sym->st_size;
185                         pstr_symname    = (char *)(pb_dynstr + p_sym->st_name);
186                         dw_status               = 0x00;
187                 }
188                 else    {
189                         // Search DynSym_Version ---
190                         i_bid                   = p_binfo->i_id;
191                         if( 1 < w_gnuver )      {
192                                 p_vernow        = p_verneed;
193                                 for( dw_cnt = 0; dw_cnt < dw_vermax; dw_cnt++, p_vernow++ )     {
194                                         if( w_gnuver == p_vernow->dw_other )    {
195                                                 i_bid                   = p_vernow->i_binfo_id;
196                                                 break;
197                                         }
198                                 }
199                         }
200
201                         if( i_bid == p_binfo->i_id )    {
202                                 i_bid           = BinInfo_SearchNextSlave( p_binfo->i_id, i_bid );
203                                 p_vernow        = NULL;
204                         }
205
206                         pstr_symname    = (char *)(pb_dynstr + p_sym->st_name);
207
208                         // Check .gnu.hash ---
209                         b_binding       = 255;
210                         i_symindex      = -0x01;
211                         while( -0x01 != i_bid )         {
212                                 p_binlib        = BinaryInfo_GetBinInfo( i_bid );
213                                 assert( NULL != p_binlib );
214
215                                 i_result        = ELF64_GnuHash_SearchDynSym(
216                                                                         p_binlib, pstr_symname, p_vernow, &b_bindtemp );
217                                 if( 0 <= i_result )             {
218                                         i_symindex      = i_result;
219                                         b_binding       = b_bindtemp;
220                                         if( STB_WEAK != b_binding )     { break; }
221                                 }
222
223                                 i_bid   = BinInfo_SearchNextSlave( p_binfo->i_id, i_bid );
224                         }
225                 
226                         if( 0 > i_symindex )    { continue; }
227
228                         // If dynsym addr = 0x00000000, Search PLT addr. from .got addr. ---
229                         //   for FreeBSD 11.x or older ---
230                         if( 0x00000000 == p_sym->st_value )     {
231                                 ptr_addr        = ELF64_Rela_GetPLTaddr_fromGOT( p_binfo, pstr_symname );
232                                 qw_size         = psec_plt->qw_entsize;
233                         }
234                         //   for FreeBSD 12.x ---
235                         else    {
236                                 ptr_addr        = (PtrValue)p_sym->st_value;
237                                 qw_size         = p_sym->st_size;
238                         }
239                         dw_status       = OBJINFO_STATUS_DYNAMIC;
240                 }
241
242                 if( 0x00000000 < ptr_addr )     {
243                         ptr_addr        += p_binfo->ptr_loadbase;
244                         p_obj   = ObjectInfo_SearchDynamicSymbol( p_pginfo, ptr_addr, pstr_symname, dw_status );
245                         // If the target program is stripped, p_obj = NULL because don't exist .symtab section.
246                         if( NULL == p_obj )     {
247                                 p_obj   = ELF64_Symtab_RegistSymbol_toObjectInfo(
248                                                                         p_pginfo, p_binfo, ptr_addr, qw_size, p_sym, pb_dynstr );
249                         }
250
251                         if(( NULL != p_obj ) && ( OBJINFO_STATUS_DYNAMIC == dw_status ))        {
252                                 p_obj->dynamic.i_binfo_origin   = i_bid;
253                                 p_obj->dynamic.i_dynsym_index   = i_symindex;
254                                 p_obj->dw_status                                |= (OBJINFO_STATUS_DYNAMIC | OBJINFO_STATUS_RESOLV1);
255                         }
256                 }
257         }
258
259         ELF64_GnuVer_FreeGnuVerNeed( p_verneed );
260
261         // If PLT entsize = 0 in .plt, ReSet PLT entsize from diffrent Next&Now PLT addr.
262         //   for FreeBSD 12.x ---
263         ELF_DynSym_ReSetPLTsize_inObjectInfo( p_pginfo, p_binfo );
264         
265         return 0x00;
266 }
267
268
269
270 /* EOF of drd64_.c ----------------------------------- */
271
272