1 /*
2  * verneed.h - copy versioning information.
3  * Copyright (C) 2001 - 2006 Michael Riepe
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #ifndef lint
21 static const char verneed_h_rcsid[] = "@(#) $Id: verneed.h,v 1.13 2008/05/23 08:15:35 michael Exp $";
22 #endif /* lint */
23 
24 #if VER_NEED_CURRENT != 1
25 #error libelf currently does not support VER_NEED_CURRENT != 1
26 #endif /* VER_NEED_CURRENT != 1 */
27 
28 #if TOFILE
29 
30 static void
__store_vernaux(vernaux_ftype * dst,const vernaux_mtype * src,unsigned enc)31 __store_vernaux(vernaux_ftype *dst, const vernaux_mtype *src, unsigned enc) {
32     if (enc == ELFDATA2LSB) {
33 	__store_u32L(dst->vna_hash,  src->vna_hash);
34 	__store_u16L(dst->vna_flags, src->vna_flags);
35 	__store_u16L(dst->vna_other, src->vna_other);
36 	__store_u32L(dst->vna_name,  src->vna_name);
37 	__store_u32L(dst->vna_next,  src->vna_next);
38     }
39     else {
40 	__store_u32M(dst->vna_hash,  src->vna_hash);
41 	__store_u16M(dst->vna_flags, src->vna_flags);
42 	__store_u16M(dst->vna_other, src->vna_other);
43 	__store_u32M(dst->vna_name,  src->vna_name);
44 	__store_u32M(dst->vna_next,  src->vna_next);
45     }
46 }
47 
48 static void
__store_verneed(verneed_ftype * dst,const verneed_mtype * src,unsigned enc)49 __store_verneed(verneed_ftype *dst, const verneed_mtype *src, unsigned enc) {
50     if (enc == ELFDATA2LSB) {
51 	__store_u16L(dst->vn_version, src->vn_version);
52 	__store_u16L(dst->vn_cnt,     src->vn_cnt);
53 	__store_u32L(dst->vn_file,    src->vn_file);
54 	__store_u32L(dst->vn_aux,     src->vn_aux);
55 	__store_u32L(dst->vn_next,    src->vn_next);
56     }
57     else {
58 	__store_u16M(dst->vn_version, src->vn_version);
59 	__store_u16M(dst->vn_cnt,     src->vn_cnt);
60 	__store_u32M(dst->vn_file,    src->vn_file);
61 	__store_u32M(dst->vn_aux,     src->vn_aux);
62 	__store_u32M(dst->vn_next,    src->vn_next);
63     }
64 }
65 
66 typedef vernaux_mtype		vernaux_stype;
67 typedef vernaux_ftype		vernaux_dtype;
68 typedef verneed_mtype		verneed_stype;
69 typedef verneed_ftype		verneed_dtype;
70 typedef align_mtype		verneed_atype;
71 
72 #define copy_vernaux_srctotmp(d, s, e)	(*(d) = *(s))
73 #define copy_vernaux_tmptodst(d, s, e)	__store_vernaux((d), (s), (e))
74 #define copy_verneed_srctotmp(d, s, e)	(*(d) = *(s))
75 #define copy_verneed_tmptodst(d, s, e)	__store_verneed((d), (s), (e))
76 
77 #define translator_suffix	_tof
78 
79 #else /* TOFILE */
80 
81 static void
__load_vernaux(vernaux_mtype * dst,const vernaux_ftype * src,unsigned enc)82 __load_vernaux(vernaux_mtype *dst, const vernaux_ftype *src, unsigned enc) {
83     if (enc == ELFDATA2LSB) {
84 	dst->vna_hash  = __load_u32L(src->vna_hash);
85 	dst->vna_flags = __load_u16L(src->vna_flags);
86 	dst->vna_other = __load_u16L(src->vna_other);
87 	dst->vna_name  = __load_u32L(src->vna_name);
88 	dst->vna_next  = __load_u32L(src->vna_next);
89     }
90     else {
91 	dst->vna_hash  = __load_u32M(src->vna_hash);
92 	dst->vna_flags = __load_u16M(src->vna_flags);
93 	dst->vna_other = __load_u16M(src->vna_other);
94 	dst->vna_name  = __load_u32M(src->vna_name);
95 	dst->vna_next  = __load_u32M(src->vna_next);
96     }
97 }
98 
99 static void
__load_verneed(verneed_mtype * dst,const verneed_ftype * src,unsigned enc)100 __load_verneed(verneed_mtype *dst, const verneed_ftype *src, unsigned enc) {
101     if (enc == ELFDATA2LSB) {
102 	dst->vn_version = __load_u16L(src->vn_version);
103 	dst->vn_cnt     = __load_u16L(src->vn_cnt);
104 	dst->vn_file    = __load_u32L(src->vn_file);
105 	dst->vn_aux     = __load_u32L(src->vn_aux);
106 	dst->vn_next    = __load_u32L(src->vn_next);
107     }
108     else {
109 	dst->vn_version = __load_u16M(src->vn_version);
110 	dst->vn_cnt     = __load_u16M(src->vn_cnt);
111 	dst->vn_file    = __load_u32M(src->vn_file);
112 	dst->vn_aux     = __load_u32M(src->vn_aux);
113 	dst->vn_next    = __load_u32M(src->vn_next);
114     }
115 }
116 
117 typedef vernaux_ftype		vernaux_stype;
118 typedef vernaux_mtype		vernaux_dtype;
119 typedef verneed_ftype		verneed_stype;
120 typedef verneed_mtype		verneed_dtype;
121 typedef align_ftype		verneed_atype;
122 
123 #define copy_vernaux_srctotmp(d, s, e)	__load_vernaux((d), (s), (e))
124 #define copy_vernaux_tmptodst(d, s, e)	(*(d) = *(s))
125 #define copy_verneed_srctotmp(d, s, e)	__load_verneed((d), (s), (e))
126 #define copy_verneed_tmptodst(d, s, e)	(*(d) = *(s))
127 
128 #define translator_suffix	_tom
129 
130 #endif /* TOFILE */
131 
132 #define cat3(a,b,c)	a##b##c
133 #define xlt3(p,e,s)	cat3(p,e,s)
134 #define xltprefix(x)	xlt3(x,_,class_suffix)
135 #define translator(x,e)	xlt3(xltprefix(_elf_##x),e,translator_suffix)
136 
137 static size_t
xlt_verneed(unsigned char * dst,const unsigned char * src,size_t n,unsigned enc)138 xlt_verneed(unsigned char *dst, const unsigned char *src, size_t n, unsigned enc) {
139     size_t off;
140 
141     if (sizeof(verneed_stype) != sizeof(verneed_dtype)
142      || sizeof(vernaux_stype) != sizeof(vernaux_dtype)) {
143 	/* never happens for ELF v1 and Verneed v1 */
144 	seterr(ERROR_UNIMPLEMENTED);
145 	return (size_t)-1;
146     }
147     /* size translation shortcut */
148     if (dst == NULL) {
149 	return n;
150     }
151     if (src == NULL) {
152 	seterr(ERROR_NULLBUF);
153 	return (size_t)-1;
154     }
155     off = 0;
156     while (off + sizeof(verneed_stype) <= n) {
157 	const verneed_stype *svn;
158 	verneed_dtype *dvn;
159 	verneed_mtype vn;
160 	size_t acount;
161 	size_t aoff;
162 
163 	/*
164 	 * check for proper alignment
165 	 */
166 	if (off % sizeof(verneed_atype)) {
167 	    seterr(ERROR_VERNEED_FORMAT);
168 	    return (size_t)-1;
169 	}
170 	/*
171 	 * copy and check src
172 	 */
173 	svn = (verneed_stype*)(src + off);
174 	dvn = (verneed_dtype*)(dst + off);
175 	copy_verneed_srctotmp(&vn, svn, enc);
176 	if (vn.vn_version < 1
177 	 || vn.vn_version > VER_NEED_CURRENT) {
178 	    seterr(ERROR_VERNEED_VERSION);
179 	    return (size_t)-1;
180 	}
181 	if (vn.vn_cnt < 1
182 	 || vn.vn_aux == 0) {
183 	    seterr(ERROR_VERNEED_FORMAT);
184 	    return (size_t)-1;
185 	}
186 	copy_verneed_tmptodst(dvn, &vn, enc);
187 	/*
188 	 * copy aux array
189 	 */
190 	aoff = off + vn.vn_aux;
191 	for (acount = 0; acount < vn.vn_cnt; acount++) {
192 	    const vernaux_stype *svna;
193 	    vernaux_dtype *dvna;
194 	    vernaux_mtype vna;
195 
196 	    /*
197 	     * are we still inside the buffer limits?
198 	     */
199 	    if (aoff + sizeof(vernaux_stype) > n) {
200 		break;
201 	    }
202 	    /*
203 	     * check for proper alignment
204 	     */
205 	    if (aoff % sizeof(verneed_atype)) {
206 		seterr(ERROR_VERNEED_FORMAT);
207 		return (size_t)-1;
208 	    }
209 	    /*
210 	     * copy and check src
211 	     */
212 	    svna = (vernaux_stype*)(src + aoff);
213 	    dvna = (vernaux_dtype*)(dst + aoff);
214 	    copy_vernaux_srctotmp(&vna, svna, enc);
215 	    copy_vernaux_tmptodst(dvna, &vna, enc);
216 	    /*
217 	     * advance to next vernaux
218 	     */
219 	    if (vna.vna_next == 0) {
220 		/* end of list */
221 		break;
222 	    }
223 	    aoff += vna.vna_next;
224 	}
225 	/*
226 	 * advance to next verneed
227 	 */
228 	if (vn.vn_next == 0) {
229 	    /* end of list */
230 	    break;
231 	}
232 	off += vn.vn_next;
233     }
234     return n;
235 }
236 
237 size_t
translator(verneed,L11)238 translator(verneed,L11)(unsigned char *dst, const unsigned char *src, size_t n) {
239     return xlt_verneed(dst, src, n, ELFDATA2LSB);
240 }
241 
242 size_t
translator(verneed,M11)243 translator(verneed,M11)(unsigned char *dst, const unsigned char *src, size_t n) {
244     return xlt_verneed(dst, src, n, ELFDATA2MSB);
245 }
246