|
1 /* |
|
2 getdata.c - implementation of the elf_getdata(3) function. |
|
3 Copyright (C) 1995 - 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 */ |
|
19 |
|
20 #include <private.h> |
|
21 |
|
22 #ifndef lint |
|
23 static const char rcsid[] = "@(#) $Id: getdata.c,v 1.12 2005/05/21 15:39:23 michael Exp $"; |
|
24 #endif /* lint */ |
|
25 |
|
26 static Elf_Data* |
|
27 _elf_cook_scn(Elf *elf, Elf_Scn *scn, Scn_Data *sd) { |
|
28 Elf_Data dst; |
|
29 Elf_Data src; |
|
30 int flag = 0; |
|
31 size_t dlen; |
|
32 |
|
33 elf_assert(elf->e_data); |
|
34 |
|
35 /* |
|
36 * Prepare source |
|
37 */ |
|
38 src = sd->sd_data; |
|
39 src.d_version = elf->e_version; |
|
40 if (elf->e_rawdata) { |
|
41 src.d_buf = elf->e_rawdata + scn->s_offset; |
|
42 } |
|
43 else { |
|
44 src.d_buf = elf->e_data + scn->s_offset; |
|
45 } |
|
46 |
|
47 /* |
|
48 * Prepare destination (needs prepared source!) |
|
49 */ |
|
50 dst = sd->sd_data; |
|
51 if (elf->e_class == ELFCLASS32) { |
|
52 dlen = _elf32_xltsize(&src, dst.d_version, elf->e_encoding, 0); |
|
53 } |
|
54 #if __LIBELF64 |
|
55 else if (elf->e_class == ELFCLASS64) { |
|
56 dlen = _elf64_xltsize(&src, dst.d_version, elf->e_encoding, 0); |
|
57 } |
|
58 #endif /* __LIBELF64 */ |
|
59 else { |
|
60 elf_assert(valid_class(elf->e_class)); |
|
61 seterr(ERROR_UNIMPLEMENTED); |
|
62 return NULL; |
|
63 } |
|
64 if (dlen == (size_t)-1) { |
|
65 return NULL; |
|
66 } |
|
67 dst.d_size = dlen; |
|
68 if (elf->e_rawdata != elf->e_data && dst.d_size <= src.d_size) { |
|
69 dst.d_buf = elf->e_data + scn->s_offset; |
|
70 } |
|
71 else if (!(dst.d_buf = malloc(dst.d_size))) { |
|
72 seterr(ERROR_MEM_SCNDATA); |
|
73 return NULL; |
|
74 } |
|
75 else { |
|
76 flag = 1; |
|
77 } |
|
78 |
|
79 /* |
|
80 * Translate data |
|
81 */ |
|
82 if (_elf_xlatetom(elf, &dst, &src)) { |
|
83 sd->sd_memdata = (char*)dst.d_buf; |
|
84 sd->sd_data = dst; |
|
85 if (!(sd->sd_free_data = flag)) { |
|
86 elf->e_cooked = 1; |
|
87 } |
|
88 return &sd->sd_data; |
|
89 } |
|
90 |
|
91 if (flag) { |
|
92 free(dst.d_buf); |
|
93 } |
|
94 return NULL; |
|
95 } |
|
96 |
|
97 Elf_Data* |
|
98 elf_getdata(Elf_Scn *scn, Elf_Data *data) { |
|
99 Scn_Data *sd; |
|
100 Elf *elf; |
|
101 |
|
102 if (!scn) { |
|
103 return NULL; |
|
104 } |
|
105 elf_assert(scn->s_magic == SCN_MAGIC); |
|
106 if (scn->s_index == SHN_UNDEF) { |
|
107 seterr(ERROR_NULLSCN); |
|
108 } |
|
109 else if (data) { |
|
110 for (sd = scn->s_data_1; sd; sd = sd->sd_link) { |
|
111 elf_assert(sd->sd_magic == DATA_MAGIC); |
|
112 elf_assert(sd->sd_scn == scn); |
|
113 if (data == &sd->sd_data) { |
|
114 /* |
|
115 * sd_link allocated by elf_newdata(). |
|
116 */ |
|
117 return &sd->sd_link->sd_data; |
|
118 } |
|
119 } |
|
120 seterr(ERROR_SCNDATAMISMATCH); |
|
121 } |
|
122 else if ((sd = scn->s_data_1)) { |
|
123 elf_assert(sd->sd_magic == DATA_MAGIC); |
|
124 elf_assert(sd->sd_scn == scn); |
|
125 elf = scn->s_elf; |
|
126 elf_assert(elf); |
|
127 elf_assert(elf->e_magic == ELF_MAGIC); |
|
128 if (sd->sd_freeme) { |
|
129 /* allocated by elf_newdata() */ |
|
130 return &sd->sd_data; |
|
131 } |
|
132 else if (scn->s_type == SHT_NULL) { |
|
133 seterr(ERROR_NULLSCN); |
|
134 } |
|
135 else if (sd->sd_memdata) { |
|
136 /* already cooked */ |
|
137 return &sd->sd_data; |
|
138 } |
|
139 else if (scn->s_offset < 0 || scn->s_offset > elf->e_size) { |
|
140 seterr(ERROR_OUTSIDE); |
|
141 } |
|
142 else if (scn->s_type == SHT_NOBITS || !scn->s_size) { |
|
143 /* no data to read */ |
|
144 return &sd->sd_data; |
|
145 } |
|
146 else if (scn->s_offset + scn->s_size > elf->e_size) { |
|
147 seterr(ERROR_TRUNC_SCN); |
|
148 } |
|
149 else if (valid_class(elf->e_class)) { |
|
150 return _elf_cook_scn(elf, scn, sd); |
|
151 } |
|
152 else { |
|
153 seterr(ERROR_UNKNOWN_CLASS); |
|
154 } |
|
155 } |
|
156 return NULL; |
|
157 } |