Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2013-2017 IBM Corp. */
3 : :
4 : : #include "hdif.h"
5 : : #include <stack.h>
6 : :
7 : : static const struct HDIF_idata_ptr *
8 : 1067 : HDIF_idata(const struct HDIF_common_hdr *hdif, unsigned int idx)
9 : : {
10 : : const struct HDIF_idata_ptr *iptr;
11 : :
12 : 1067 : if (!HDIF_check(hdif, NULL)) {
13 : 0 : prerror("HDIF: Bad header format !\n");
14 : 0 : backtrace();
15 : 0 : return NULL;
16 : : }
17 : :
18 : 1067 : if (idx >= be16_to_cpu(hdif->idptr_count)) {
19 : 1 : prlog(PR_DEBUG, "HDIF: idata %d out of range for %.6s!\n",
20 : : idx, hdif->id);
21 : 1 : return NULL;
22 : : }
23 : :
24 : 1066 : iptr = (void *)hdif + be32_to_cpu(hdif->idptr_off);
25 : :
26 : 1066 : return &iptr[idx];
27 : : }
28 : :
29 : 1067 : const void *HDIF_get_idata(const struct HDIF_common_hdr *hdif, unsigned int di,
30 : : unsigned int *size)
31 : : {
32 : : const struct HDIF_idata_ptr *iptr;
33 : :
34 : 1067 : iptr = HDIF_idata(hdif, di);
35 : 1067 : if (!iptr)
36 : 1 : return NULL;
37 : :
38 : 1066 : if (size)
39 : 969 : *size = be32_to_cpu(iptr->size);
40 : :
41 : 1066 : return (void *)hdif + be32_to_cpu(iptr->offset);
42 : : }
43 : :
44 : 598 : const void *HDIF_get_iarray_item(const struct HDIF_common_hdr *hdif,
45 : : unsigned int di, unsigned int ai,
46 : : unsigned int *size)
47 : : {
48 : : const struct HDIF_array_hdr *ahdr;
49 : : unsigned int asize;
50 : : const void *arr;
51 : :
52 : 598 : arr = HDIF_get_idata(hdif, di, &asize);
53 : 598 : if (!arr)
54 : 0 : return NULL;
55 : :
56 : 598 : if (asize < sizeof(struct HDIF_array_hdr)) {
57 : 0 : prerror("HDIF: idata block too small for array !\n");
58 : 0 : backtrace();
59 : 0 : return NULL;
60 : : }
61 : :
62 : 598 : ahdr = arr;
63 : :
64 : 598 : if (ai >= be32_to_cpu(ahdr->ecnt)) {
65 : 0 : prerror("HDIF: idata array index out of range !\n");
66 : 0 : backtrace();
67 : 0 : return NULL;
68 : : }
69 : :
70 : 598 : if (size)
71 : 597 : *size = be32_to_cpu(ahdr->eactsz);
72 : :
73 : 598 : return arr + be32_to_cpu(ahdr->offset) + ai * be32_to_cpu(ahdr->esize);
74 : : }
75 : :
76 : 253 : int HDIF_get_iarray_size(const struct HDIF_common_hdr *hdif, unsigned int di)
77 : : {
78 : : const struct HDIF_array_hdr *ahdr;
79 : : unsigned int asize;
80 : : const void *arr;
81 : :
82 : 253 : arr = HDIF_get_idata(hdif, di, &asize);
83 : 253 : if (!arr)
84 : 0 : return -1;
85 : :
86 : 253 : if (asize < sizeof(struct HDIF_array_hdr)) {
87 : 0 : prerror("HDIF: idata block too small for array !\n");
88 : 0 : backtrace();
89 : 0 : return -1;
90 : : }
91 : :
92 : 253 : ahdr = arr;
93 : 253 : return be32_to_cpu(ahdr->ecnt);
94 : : }
95 : :
96 : : /*
97 : : * Returns NULL and sets *items to zero when:
98 : : *
99 : : * a) Array extends beyond bounds (hard error)
100 : : * b) The array is empty (soft error)
101 : : * c) The item size is zero (soft error)
102 : : * d) The array is missing (soft error)
103 : : *
104 : : * b, c) are bugs in the input data so they generate backtraces.
105 : : *
106 : : * If you care about the soft error cases, retrive the array header manually
107 : : * with HDIF_get_idata().
108 : : */
109 : 1 : const struct HDIF_array_hdr *HDIF_get_iarray(const struct HDIF_common_hdr *hdif,
110 : : unsigned int di, unsigned int *items)
111 : : {
112 : : const struct HDIF_array_hdr *arr;
113 : : unsigned int req_size, size, elements;
114 : : unsigned int actual_sz, alloc_sz, offset;
115 : :
116 : 1 : arr = HDIF_get_idata(hdif, di, &size);
117 : :
118 : 1 : if(items)
119 : 1 : *items = 0;
120 : :
121 : 1 : if (!arr || !size)
122 : 1 : return NULL;
123 : :
124 : : /* base size of an Idata array header */
125 : 0 : offset = be32_to_cpu(arr->offset);
126 : 0 : actual_sz = be32_to_cpu(arr->eactsz);
127 : 0 : alloc_sz = be32_to_cpu(arr->esize);
128 : 0 : elements = be32_to_cpu(arr->ecnt);
129 : :
130 : : /* actual size should always be smaller than allocated */
131 : 0 : if (alloc_sz < actual_sz) {
132 : 0 : prerror("HDIF %.6s iarray %u has actsz (%u) < alloc_sz (%u)\n)",
133 : : hdif->id, di, actual_sz, alloc_sz);
134 : 0 : backtrace();
135 : 0 : return NULL;
136 : : }
137 : :
138 : 0 : req_size = elements * alloc_sz + offset;
139 : 0 : if (req_size > size) {
140 : 0 : prerror("HDIF: %.6s iarray %u requires %#x bytes, but only %#x are allocated!\n",
141 : : hdif->id, di, req_size, size);
142 : 0 : backtrace();
143 : 0 : return NULL;
144 : : }
145 : :
146 : 0 : if (!elements || !actual_sz)
147 : 0 : return NULL;
148 : :
149 : 0 : if (items)
150 : 0 : *items = elements;
151 : :
152 : 0 : return arr;
153 : : }
154 : :
155 : 0 : const void *HDIF_iarray_item(const struct HDIF_array_hdr *ahdr,
156 : : unsigned int index)
157 : : {
158 : 0 : if (!ahdr || index >= be32_to_cpu(ahdr->ecnt))
159 : 0 : return NULL;
160 : :
161 : 0 : return (const void * )ahdr + be32_to_cpu(ahdr->offset) +
162 : 0 : index * be32_to_cpu(ahdr->esize);
163 : : }
164 : :
165 : : struct HDIF_child_ptr *
166 : 5 : HDIF_child_arr(const struct HDIF_common_hdr *hdif, unsigned int idx)
167 : : {
168 : : struct HDIF_child_ptr *children;
169 : :
170 : 5 : if (!HDIF_check(hdif, NULL)) {
171 : 0 : prerror("HDIF: Bad header format !\n");
172 : 0 : backtrace();
173 : 0 : return NULL;
174 : : }
175 : :
176 : 5 : children = (void *)hdif + be32_to_cpu(hdif->child_off);
177 : :
178 : 5 : if (idx >= be16_to_cpu(hdif->child_count)) {
179 : 0 : prerror("HDIF: child array idx out of range!\n");
180 : 0 : backtrace();
181 : 0 : return NULL;
182 : : }
183 : :
184 : 5 : return &children[idx];
185 : : }
186 : :
187 : 6 : struct HDIF_common_hdr *HDIF_child(const struct HDIF_common_hdr *hdif,
188 : : const struct HDIF_child_ptr *child,
189 : : unsigned int idx,
190 : : const char *eyecatcher)
191 : : {
192 : 6 : void *base = (void *)hdif;
193 : : struct HDIF_common_hdr *ret;
194 : : long child_off;
195 : :
196 : 6 : if (!HDIF_check(hdif, NULL)) {
197 : 0 : prerror("HDIF: Bad header format !\n");
198 : 0 : backtrace();
199 : 0 : return NULL;
200 : : }
201 : :
202 : : /* child must be in hdif's child array */
203 : 6 : child_off = (void *)child - (base + be32_to_cpu(hdif->child_off));
204 : 6 : assert(child_off % sizeof(struct HDIF_child_ptr) == 0);
205 : 6 : assert(child_off / sizeof(struct HDIF_child_ptr)
206 : : < be16_to_cpu(hdif->child_count));
207 : :
208 : 6 : assert(idx < be32_to_cpu(child->count));
209 : :
210 : 6 : if (be32_to_cpu(child->size) < sizeof(struct HDIF_common_hdr)) {
211 : 0 : prerror("HDIF: %s child #%i too small: %u\n",
212 : : eyecatcher, idx, be32_to_cpu(child->size));
213 : 0 : backtrace();
214 : 0 : return NULL;
215 : : }
216 : :
217 : 6 : ret = base + be32_to_cpu(child->offset)
218 : 6 : + be32_to_cpu(child->size) * idx;
219 : 6 : if (!HDIF_check(ret, eyecatcher)) {
220 : 0 : prerror("HDIF: #%i bad type (wanted %6s, got %6s)\n",
221 : : idx, eyecatcher, ret->id);
222 : 0 : backtrace();
223 : 0 : return NULL;
224 : : }
225 : :
226 : 6 : return ret;
227 : : }
|