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