1/* Conversion functions for versioning information.
2   Copyright (C) 1998, 1999, 2000, 2002, 2003, 2015 Red Hat, Inc.
3   This file is part of elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#include <assert.h>
31#include <gelf.h>
32
33#include "libelfP.h"
34
35
36static void
37elf_cvt_Verdef (void *dest, const void *src, size_t len, int encode)
38{
39  /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux.
40     To recognize them we have to walk the data structure and convert
41     them one after the other.  The ENCODE parameter specifies whether
42     we are encoding or decoding.  When we are encoding we can immediately
43     use the data in the buffer; if not, we have to decode the data before
44     using it.  */
45  size_t def_offset = 0;
46  GElf_Verdef *ddest;
47  GElf_Verdef *dsrc;
48
49  /* We rely on the types being all the same size.  */
50  assert (sizeof (GElf_Verdef) == sizeof (Elf32_Verdef));
51  assert (sizeof (GElf_Verdaux) == sizeof (Elf32_Verdaux));
52  assert (sizeof (GElf_Verdef) == sizeof (Elf64_Verdef));
53  assert (sizeof (GElf_Verdaux) == sizeof (Elf64_Verdaux));
54
55  if (len == 0)
56    return;
57
58  /* Below we rely on the next field offsets to be correct, start by
59     copying over all data as is in case some data isn't translated.
60     We don't want to leave (undefined) garbage in the dest buffer.  */
61  memmove (dest, src, len);
62
63  do
64    {
65      size_t aux_offset;
66      GElf_Verdaux *asrc;
67
68      /* Test for correct offset.  */
69      if (def_offset > len || len - def_offset < sizeof (GElf_Verdef))
70	return;
71
72      /* Work the tree from the first record.  */
73      ddest = (GElf_Verdef *) ((char *) dest + def_offset);
74      dsrc = (GElf_Verdef *) ((char *) src + def_offset);
75
76      /* Decode first if necessary.  */
77      if (! encode)
78	{
79	  ddest->vd_version = bswap_16 (dsrc->vd_version);
80	  ddest->vd_flags = bswap_16 (dsrc->vd_flags);
81	  ddest->vd_ndx = bswap_16 (dsrc->vd_ndx);
82	  ddest->vd_cnt = bswap_16 (dsrc->vd_cnt);
83	  ddest->vd_hash = bswap_32 (dsrc->vd_hash);
84	  ddest->vd_aux = bswap_32 (dsrc->vd_aux);
85	  ddest->vd_next = bswap_32 (dsrc->vd_next);
86
87	  aux_offset = def_offset + ddest->vd_aux;
88	}
89      else
90	aux_offset = def_offset + dsrc->vd_aux;
91
92      /* Handle all the auxiliary records belonging to this definition.  */
93      do
94	{
95	  GElf_Verdaux *adest;
96
97	  /* Test for correct offset.  */
98	  if (aux_offset > len || len - aux_offset < sizeof (GElf_Verdaux))
99	    return;
100
101	  adest = (GElf_Verdaux *) ((char *) dest + aux_offset);
102	  asrc = (GElf_Verdaux *) ((char *) src + aux_offset);
103
104	  if (encode)
105	    aux_offset += asrc->vda_next;
106
107	  adest->vda_name = bswap_32 (asrc->vda_name);
108	  adest->vda_next = bswap_32 (asrc->vda_next);
109
110	  if (! encode)
111	    aux_offset += adest->vda_next;
112	}
113      while (asrc->vda_next != 0);
114
115      /* Encode now if necessary.  */
116      if (encode)
117	{
118	  def_offset += dsrc->vd_next;
119
120	  ddest->vd_version = bswap_16 (dsrc->vd_version);
121	  ddest->vd_flags = bswap_16 (dsrc->vd_flags);
122	  ddest->vd_ndx = bswap_16 (dsrc->vd_ndx);
123	  ddest->vd_cnt = bswap_16 (dsrc->vd_cnt);
124	  ddest->vd_hash = bswap_32 (dsrc->vd_hash);
125	  ddest->vd_aux = bswap_32 (dsrc->vd_aux);
126	  ddest->vd_next = bswap_32 (dsrc->vd_next);
127	}
128      else
129	def_offset += ddest->vd_next;
130    }
131  while (dsrc->vd_next != 0);
132}
133
134
135static void
136elf_cvt_Verneed (void *dest, const void *src, size_t len, int encode)
137{
138  /* We have two different record types: ElfXX_Verndef and ElfXX_Verdaux.
139     To recognize them we have to walk the data structure and convert
140     them one after the other.  The ENCODE parameter specifies whether
141     we are encoding or decoding.  When we are encoding we can immediately
142     use the data in the buffer; if not, we have to decode the data before
143     using it.  */
144  size_t need_offset = 0;
145  GElf_Verneed *ndest;
146  GElf_Verneed *nsrc;
147
148  /* We rely on the types being all the same size.  */
149  assert (sizeof (GElf_Verneed) == sizeof (Elf32_Verneed));
150  assert (sizeof (GElf_Vernaux) == sizeof (Elf32_Vernaux));
151  assert (sizeof (GElf_Verneed) == sizeof (Elf64_Verneed));
152  assert (sizeof (GElf_Vernaux) == sizeof (Elf64_Vernaux));
153
154  if (len == 0)
155    return;
156
157  /* Below we rely on the next field offsets to be correct, start by
158     copying over all data as is in case some data isn't translated.
159     We don't want to leave (undefined) garbage in the dest buffer.  */
160  memmove (dest, src, len);
161
162  do
163    {
164      size_t aux_offset;
165      GElf_Vernaux *asrc;
166
167      /* Test for correct offset.  */
168      if (need_offset > len || len - need_offset < sizeof (GElf_Verneed))
169	return;
170
171      /* Work the tree from the first record.  */
172      ndest = (GElf_Verneed *) ((char *) dest + need_offset);
173      nsrc = (GElf_Verneed *) ((char *) src + need_offset);
174
175      /* Decode first if necessary.  */
176      if (! encode)
177	{
178	  ndest->vn_version = bswap_16 (nsrc->vn_version);
179	  ndest->vn_cnt = bswap_16 (nsrc->vn_cnt);
180	  ndest->vn_file = bswap_32 (nsrc->vn_file);
181	  ndest->vn_aux = bswap_32 (nsrc->vn_aux);
182	  ndest->vn_next = bswap_32 (nsrc->vn_next);
183
184	  aux_offset = need_offset + ndest->vn_aux;
185	}
186      else
187	aux_offset = need_offset + nsrc->vn_aux;
188
189      /* Handle all the auxiliary records belonging to this requirement.  */
190      do
191	{
192	  GElf_Vernaux *adest;
193
194	  /* Test for correct offset.  */
195	  if (aux_offset > len || len - aux_offset < sizeof (GElf_Vernaux))
196	    return;
197
198	  adest = (GElf_Vernaux *) ((char *) dest + aux_offset);
199	  asrc = (GElf_Vernaux *) ((char *) src + aux_offset);
200
201	  if (encode)
202	    aux_offset += asrc->vna_next;
203
204	  adest->vna_hash = bswap_32 (asrc->vna_hash);
205	  adest->vna_flags = bswap_16 (asrc->vna_flags);
206	  adest->vna_other = bswap_16 (asrc->vna_other);
207	  adest->vna_name = bswap_32 (asrc->vna_name);
208	  adest->vna_next = bswap_32 (asrc->vna_next);
209
210	  if (! encode)
211	    aux_offset += adest->vna_next;
212	}
213      while (asrc->vna_next != 0);
214
215      /* Encode now if necessary.  */
216      if (encode)
217	{
218	  need_offset += nsrc->vn_next;
219
220	  ndest->vn_version = bswap_16 (nsrc->vn_version);
221	  ndest->vn_cnt = bswap_16 (nsrc->vn_cnt);
222	  ndest->vn_file = bswap_32 (nsrc->vn_file);
223	  ndest->vn_aux = bswap_32 (nsrc->vn_aux);
224	  ndest->vn_next = bswap_32 (nsrc->vn_next);
225	}
226      else
227	need_offset += ndest->vn_next;
228    }
229  while (nsrc->vn_next != 0);
230}
231