pdb.c revision 1.1.1.1 1 1.1 christos /* BFD back-end for PDB Multi-Stream Format archives.
2 1.1 christos Copyright (C) 2022 Free Software Foundation, Inc.
3 1.1 christos
4 1.1 christos This file is part of BFD, the Binary File Descriptor library.
5 1.1 christos
6 1.1 christos This program is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program; if not, write to the Free Software
18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 1.1 christos MA 02110-1301, USA. */
20 1.1 christos
21 1.1 christos /* This describes the MSF file archive format, which is used for the
22 1.1 christos PDB debug info generated by MSVC. See https://llvm.org/docs/PDB/MsfFile.html
23 1.1 christos for a full description of the format. */
24 1.1 christos
25 1.1 christos #include "sysdep.h"
26 1.1 christos #include "bfd.h"
27 1.1 christos #include "libbfd.h"
28 1.1 christos
29 1.1 christos /* "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\0\0\0" */
30 1.1 christos static const uint8_t pdb_magic[] =
31 1.1 christos { 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66,
32 1.1 christos 0x74, 0x20, 0x43, 0x2f, 0x43, 0x2b, 0x2b, 0x20,
33 1.1 christos 0x4d, 0x53, 0x46, 0x20, 0x37, 0x2e, 0x30, 0x30,
34 1.1 christos 0x0d, 0x0a, 0x1a, 0x44, 0x53, 0x00, 0x00, 0x00 };
35 1.1 christos
36 1.1 christos #define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data))
37 1.1 christos
38 1.1 christos static bfd_cleanup
39 1.1 christos pdb_archive_p (bfd *abfd)
40 1.1 christos {
41 1.1 christos int ret;
42 1.1 christos char magic[sizeof (pdb_magic)];
43 1.1 christos
44 1.1 christos ret = bfd_bread (magic, sizeof (magic), abfd);
45 1.1 christos if (ret != sizeof (magic))
46 1.1 christos {
47 1.1 christos bfd_set_error (bfd_error_wrong_format);
48 1.1 christos return NULL;
49 1.1 christos }
50 1.1 christos
51 1.1 christos if (memcmp (magic, pdb_magic, sizeof (magic)))
52 1.1 christos {
53 1.1 christos bfd_set_error (bfd_error_wrong_format);
54 1.1 christos return NULL;
55 1.1 christos }
56 1.1 christos
57 1.1 christos void *tdata = bfd_zalloc (abfd, sizeof (struct artdata));
58 1.1 christos if (tdata == NULL)
59 1.1 christos return NULL;
60 1.1 christos bfd_ardata (abfd) = tdata;
61 1.1 christos
62 1.1 christos return _bfd_no_cleanup;
63 1.1 christos }
64 1.1 christos
65 1.1 christos static bfd *
66 1.1 christos pdb_get_elt_at_index (bfd *abfd, symindex sym_index)
67 1.1 christos {
68 1.1 christos char int_buf[sizeof (uint32_t)];
69 1.1 christos uint32_t block_size, block_map_addr, block, num_files;
70 1.1 christos uint32_t first_dir_block, dir_offset, file_size, block_off, left;
71 1.1 christos char name[10];
72 1.1 christos bfd *file;
73 1.1 christos char *buf;
74 1.1 christos
75 1.1 christos /* Get block_size. */
76 1.1 christos
77 1.1 christos if (bfd_seek (abfd, sizeof (pdb_magic), SEEK_SET))
78 1.1 christos return NULL;
79 1.1 christos
80 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
81 1.1 christos {
82 1.1 christos bfd_set_error (bfd_error_malformed_archive);
83 1.1 christos return NULL;
84 1.1 christos }
85 1.1 christos
86 1.1 christos block_size = bfd_getl32 (int_buf);
87 1.1 christos if ((block_size & -block_size) != block_size
88 1.1 christos || block_size < 512
89 1.1 christos || block_size > 4096)
90 1.1 christos {
91 1.1 christos bfd_set_error (bfd_error_malformed_archive);
92 1.1 christos return NULL;
93 1.1 christos }
94 1.1 christos
95 1.1 christos /* Get block_map_addr. */
96 1.1 christos
97 1.1 christos if (bfd_seek (abfd, 4 * sizeof (uint32_t), SEEK_CUR))
98 1.1 christos return NULL;
99 1.1 christos
100 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
101 1.1 christos {
102 1.1 christos bfd_set_error (bfd_error_malformed_archive);
103 1.1 christos return NULL;
104 1.1 christos }
105 1.1 christos
106 1.1 christos block_map_addr = bfd_getl32 (int_buf);
107 1.1 christos
108 1.1 christos /* Get num_files. */
109 1.1 christos
110 1.1 christos if (bfd_seek (abfd, block_map_addr * block_size, SEEK_SET))
111 1.1 christos return NULL;
112 1.1 christos
113 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
114 1.1 christos {
115 1.1 christos bfd_set_error (bfd_error_malformed_archive);
116 1.1 christos return NULL;
117 1.1 christos }
118 1.1 christos
119 1.1 christos first_dir_block = bfd_getl32 (int_buf);
120 1.1 christos
121 1.1 christos if (bfd_seek (abfd, first_dir_block * block_size, SEEK_SET))
122 1.1 christos return NULL;
123 1.1 christos
124 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
125 1.1 christos {
126 1.1 christos bfd_set_error (bfd_error_malformed_archive);
127 1.1 christos return NULL;
128 1.1 christos }
129 1.1 christos
130 1.1 christos num_files = bfd_getl32 (int_buf);
131 1.1 christos
132 1.1 christos if (sym_index >= num_files)
133 1.1 christos {
134 1.1 christos bfd_set_error (bfd_error_no_more_archived_files);
135 1.1 christos return NULL;
136 1.1 christos }
137 1.1 christos
138 1.1 christos /* Read file size. */
139 1.1 christos
140 1.1 christos dir_offset = sizeof (uint32_t) * (sym_index + 1);
141 1.1 christos
142 1.1 christos if (dir_offset >= block_size)
143 1.1 christos {
144 1.1 christos uint32_t block_map_addr_off;
145 1.1 christos
146 1.1 christos block_map_addr_off = ((dir_offset / block_size) * sizeof (uint32_t));
147 1.1 christos
148 1.1 christos if (bfd_seek (abfd, (block_map_addr * block_size) + block_map_addr_off,
149 1.1 christos SEEK_SET))
150 1.1 christos return NULL;
151 1.1 christos
152 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
153 1.1 christos {
154 1.1 christos bfd_set_error (bfd_error_malformed_archive);
155 1.1 christos return NULL;
156 1.1 christos }
157 1.1 christos
158 1.1 christos block = bfd_getl32 (int_buf);
159 1.1 christos }
160 1.1 christos else
161 1.1 christos {
162 1.1 christos block = first_dir_block;
163 1.1 christos }
164 1.1 christos
165 1.1 christos if (bfd_seek (abfd, (block * block_size) + (dir_offset % block_size),
166 1.1 christos SEEK_SET))
167 1.1 christos return NULL;
168 1.1 christos
169 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
170 1.1 christos {
171 1.1 christos bfd_set_error (bfd_error_malformed_archive);
172 1.1 christos return NULL;
173 1.1 christos }
174 1.1 christos
175 1.1 christos file_size = bfd_getl32 (int_buf);
176 1.1 christos
177 1.1 christos /* Undocumented? Seen on PDBs created by MSVC 2022. */
178 1.1 christos if (file_size == 0xffffffff)
179 1.1 christos file_size = 0;
180 1.1 christos
181 1.1 christos /* Create BFD. */
182 1.1 christos
183 1.1 christos /* Four hex digits is enough - even though MSF allows for 32 bits, the
184 1.1 christos PDB format itself only uses 16 bits for stream numbers. */
185 1.1 christos sprintf (name, "%04lx", sym_index);
186 1.1 christos
187 1.1 christos file = bfd_create (name, abfd);
188 1.1 christos
189 1.1 christos if (!file)
190 1.1 christos return NULL;
191 1.1 christos
192 1.1 christos if (!bfd_make_writable (file))
193 1.1 christos goto fail;
194 1.1 christos
195 1.1 christos file->arelt_data =
196 1.1 christos (struct areltdata *) bfd_zmalloc (sizeof (struct areltdata));
197 1.1 christos
198 1.1 christos if (!file->arelt_data)
199 1.1 christos goto fail;
200 1.1 christos
201 1.1 christos arch_eltdata (file)->parsed_size = file_size;
202 1.1 christos arch_eltdata (file)->key = sym_index;
203 1.1 christos
204 1.1 christos if (file_size == 0)
205 1.1 christos return file;
206 1.1 christos
207 1.1 christos block_off = 0;
208 1.1 christos
209 1.1 christos /* Sum number of blocks in previous files. */
210 1.1 christos
211 1.1 christos if (sym_index != 0)
212 1.1 christos {
213 1.1 christos dir_offset = sizeof (uint32_t);
214 1.1 christos
215 1.1 christos if (bfd_seek (abfd, (first_dir_block * block_size) + sizeof (uint32_t),
216 1.1 christos SEEK_SET))
217 1.1 christos goto fail;
218 1.1 christos
219 1.1 christos for (symindex i = 0; i < sym_index; i++)
220 1.1 christos {
221 1.1 christos uint32_t size, num_blocks;
222 1.1 christos
223 1.1 christos if ((dir_offset % block_size) == 0)
224 1.1 christos {
225 1.1 christos uint32_t block_map_addr_off;
226 1.1 christos
227 1.1 christos block_map_addr_off =
228 1.1 christos ((dir_offset / block_size) * sizeof (uint32_t));
229 1.1 christos
230 1.1 christos if (bfd_seek
231 1.1 christos (abfd, (block_map_addr * block_size) + block_map_addr_off,
232 1.1 christos SEEK_SET))
233 1.1 christos goto fail;
234 1.1 christos
235 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) !=
236 1.1 christos sizeof (uint32_t))
237 1.1 christos {
238 1.1 christos bfd_set_error (bfd_error_malformed_archive);
239 1.1 christos goto fail;
240 1.1 christos }
241 1.1 christos
242 1.1 christos block = bfd_getl32 (int_buf);
243 1.1 christos
244 1.1 christos if (bfd_seek (abfd, block * block_size, SEEK_SET))
245 1.1 christos goto fail;
246 1.1 christos }
247 1.1 christos
248 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) !=
249 1.1 christos sizeof (uint32_t))
250 1.1 christos {
251 1.1 christos bfd_set_error (bfd_error_malformed_archive);
252 1.1 christos goto fail;
253 1.1 christos }
254 1.1 christos
255 1.1 christos size = bfd_getl32 (int_buf);
256 1.1 christos
257 1.1 christos if (size == 0xffffffff)
258 1.1 christos size = 0;
259 1.1 christos
260 1.1 christos num_blocks = (size + block_size - 1) / block_size;
261 1.1 christos block_off += num_blocks;
262 1.1 christos
263 1.1 christos dir_offset += sizeof (uint32_t);
264 1.1 christos }
265 1.1 christos }
266 1.1 christos
267 1.1 christos /* Read blocks, and write into new BFD. */
268 1.1 christos
269 1.1 christos dir_offset = sizeof (uint32_t) * (num_files + block_off + 1);
270 1.1 christos
271 1.1 christos if (dir_offset >= block_size)
272 1.1 christos {
273 1.1 christos uint32_t block_map_addr_off;
274 1.1 christos
275 1.1 christos block_map_addr_off = ((dir_offset / block_size) * sizeof (uint32_t));
276 1.1 christos
277 1.1 christos if (bfd_seek (abfd, (block_map_addr * block_size) + block_map_addr_off,
278 1.1 christos SEEK_SET))
279 1.1 christos goto fail;
280 1.1 christos
281 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
282 1.1 christos {
283 1.1 christos bfd_set_error (bfd_error_malformed_archive);
284 1.1 christos goto fail;
285 1.1 christos }
286 1.1 christos
287 1.1 christos block = bfd_getl32 (int_buf);
288 1.1 christos }
289 1.1 christos else
290 1.1 christos {
291 1.1 christos block = first_dir_block;
292 1.1 christos }
293 1.1 christos
294 1.1 christos buf = bfd_malloc (block_size);
295 1.1 christos if (!buf)
296 1.1 christos goto fail;
297 1.1 christos
298 1.1 christos left = file_size;
299 1.1 christos do
300 1.1 christos {
301 1.1 christos uint32_t file_block, to_read;
302 1.1 christos
303 1.1 christos if ((dir_offset % block_size) == 0 && left != file_size)
304 1.1 christos {
305 1.1 christos uint32_t block_map_addr_off;
306 1.1 christos
307 1.1 christos block_map_addr_off =
308 1.1 christos ((dir_offset / block_size) * sizeof (uint32_t));
309 1.1 christos
310 1.1 christos if (bfd_seek
311 1.1 christos (abfd, (block_map_addr * block_size) + block_map_addr_off,
312 1.1 christos SEEK_SET))
313 1.1 christos goto fail2;
314 1.1 christos
315 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) !=
316 1.1 christos sizeof (uint32_t))
317 1.1 christos {
318 1.1 christos bfd_set_error (bfd_error_malformed_archive);
319 1.1 christos goto fail2;
320 1.1 christos }
321 1.1 christos
322 1.1 christos block = bfd_getl32 (int_buf);
323 1.1 christos }
324 1.1 christos
325 1.1 christos if (bfd_seek (abfd, (block * block_size) + (dir_offset % block_size),
326 1.1 christos SEEK_SET))
327 1.1 christos goto fail2;
328 1.1 christos
329 1.1 christos if (bfd_bread (int_buf, sizeof (uint32_t), abfd) != sizeof (uint32_t))
330 1.1 christos {
331 1.1 christos bfd_set_error (bfd_error_malformed_archive);
332 1.1 christos goto fail2;
333 1.1 christos }
334 1.1 christos
335 1.1 christos file_block = bfd_getl32 (int_buf);
336 1.1 christos
337 1.1 christos if (bfd_seek (abfd, file_block * block_size, SEEK_SET))
338 1.1 christos goto fail2;
339 1.1 christos
340 1.1 christos to_read = left > block_size ? block_size : left;
341 1.1 christos
342 1.1 christos if (bfd_bread (buf, to_read, abfd) != to_read)
343 1.1 christos {
344 1.1 christos bfd_set_error (bfd_error_malformed_archive);
345 1.1 christos goto fail2;
346 1.1 christos }
347 1.1 christos
348 1.1 christos if (bfd_bwrite (buf, to_read, file) != to_read)
349 1.1 christos goto fail2;
350 1.1 christos
351 1.1 christos if (left > block_size)
352 1.1 christos left -= block_size;
353 1.1 christos else
354 1.1 christos break;
355 1.1 christos
356 1.1 christos dir_offset += sizeof (uint32_t);
357 1.1 christos }
358 1.1 christos while (left > 0);
359 1.1 christos
360 1.1 christos free (buf);
361 1.1 christos
362 1.1 christos return file;
363 1.1 christos
364 1.1 christos fail2:
365 1.1 christos free (buf);
366 1.1 christos
367 1.1 christos fail:
368 1.1 christos bfd_close (file);
369 1.1 christos return NULL;
370 1.1 christos }
371 1.1 christos
372 1.1 christos static bfd *
373 1.1 christos pdb_openr_next_archived_file (bfd *archive, bfd *last_file)
374 1.1 christos {
375 1.1 christos if (!last_file)
376 1.1 christos return pdb_get_elt_at_index (archive, 0);
377 1.1 christos else
378 1.1 christos return pdb_get_elt_at_index (archive, arch_eltdata (last_file)->key + 1);
379 1.1 christos }
380 1.1 christos
381 1.1 christos static int
382 1.1 christos pdb_generic_stat_arch_elt (bfd *abfd, struct stat *buf)
383 1.1 christos {
384 1.1 christos buf->st_mtime = 0;
385 1.1 christos buf->st_uid = 0;
386 1.1 christos buf->st_gid = 0;
387 1.1 christos buf->st_mode = 0644;
388 1.1 christos buf->st_size = arch_eltdata (abfd)->parsed_size;
389 1.1 christos
390 1.1 christos return 0;
391 1.1 christos }
392 1.1 christos
393 1.1 christos static uint32_t
394 1.1 christos pdb_allocate_block (uint32_t *num_blocks, uint32_t block_size)
395 1.1 christos {
396 1.1 christos uint32_t block;
397 1.1 christos
398 1.1 christos block = *num_blocks;
399 1.1 christos
400 1.1 christos (*num_blocks)++;
401 1.1 christos
402 1.1 christos /* If new interval, skip two blocks for free space map. */
403 1.1 christos
404 1.1 christos if ((block % block_size) == 1)
405 1.1 christos {
406 1.1 christos block += 2;
407 1.1 christos (*num_blocks) += 2;
408 1.1 christos }
409 1.1 christos
410 1.1 christos return block;
411 1.1 christos }
412 1.1 christos
413 1.1 christos static bool
414 1.1 christos pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files,
415 1.1 christos uint32_t block_map_addr, uint32_t * num_blocks)
416 1.1 christos {
417 1.1 christos char tmp[sizeof (uint32_t)];
418 1.1 christos uint32_t block, left, block_map_off;
419 1.1 christos bfd *arelt;
420 1.1 christos char *buf;
421 1.1 christos
422 1.1 christos /* Allocate first block for directory. */
423 1.1 christos
424 1.1 christos block = pdb_allocate_block (num_blocks, block_size);
425 1.1 christos left = block_size;
426 1.1 christos
427 1.1 christos /* Write allocated block no. at beginning of block map. */
428 1.1 christos
429 1.1 christos if (bfd_seek (abfd, block_map_addr * block_size, SEEK_SET))
430 1.1 christos return false;
431 1.1 christos
432 1.1 christos bfd_putl32 (block, tmp);
433 1.1 christos
434 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
435 1.1 christos return false;
436 1.1 christos
437 1.1 christos block_map_off = sizeof (uint32_t);
438 1.1 christos
439 1.1 christos /* Write num_files at beginning of directory. */
440 1.1 christos
441 1.1 christos if (bfd_seek (abfd, block * block_size, SEEK_SET))
442 1.1 christos return false;
443 1.1 christos
444 1.1 christos bfd_putl32 (num_files, tmp);
445 1.1 christos
446 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
447 1.1 christos return false;
448 1.1 christos
449 1.1 christos left -= sizeof (uint32_t);
450 1.1 christos
451 1.1 christos /* Write file sizes. */
452 1.1 christos
453 1.1 christos arelt = abfd->archive_head;
454 1.1 christos while (arelt)
455 1.1 christos {
456 1.1 christos if (left == 0)
457 1.1 christos {
458 1.1 christos if (block_map_off == block_size) /* Too many blocks. */
459 1.1 christos {
460 1.1 christos bfd_set_error (bfd_error_invalid_operation);
461 1.1 christos return false;
462 1.1 christos }
463 1.1 christos
464 1.1 christos block = pdb_allocate_block (num_blocks, block_size);
465 1.1 christos left = block_size;
466 1.1 christos
467 1.1 christos if (bfd_seek
468 1.1 christos (abfd, (block_map_addr * block_size) + block_map_off, SEEK_SET))
469 1.1 christos return false;
470 1.1 christos
471 1.1 christos bfd_putl32 (block, tmp);
472 1.1 christos
473 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
474 1.1 christos return false;
475 1.1 christos
476 1.1 christos block_map_off += sizeof (uint32_t);
477 1.1 christos
478 1.1 christos if (bfd_seek (abfd, block * block_size, SEEK_SET))
479 1.1 christos return false;
480 1.1 christos }
481 1.1 christos
482 1.1 christos bfd_putl32 (bfd_get_size (arelt), tmp);
483 1.1 christos
484 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
485 1.1 christos return false;
486 1.1 christos
487 1.1 christos left -= sizeof (uint32_t);
488 1.1 christos
489 1.1 christos arelt = arelt->archive_next;
490 1.1 christos }
491 1.1 christos
492 1.1 christos /* Write blocks. */
493 1.1 christos
494 1.1 christos buf = bfd_malloc (block_size);
495 1.1 christos if (!buf)
496 1.1 christos return false;
497 1.1 christos
498 1.1 christos arelt = abfd->archive_head;
499 1.1 christos while (arelt)
500 1.1 christos {
501 1.1 christos ufile_ptr size = bfd_get_size (arelt);
502 1.1 christos uint32_t req_blocks = (size + block_size - 1) / block_size;
503 1.1 christos
504 1.1 christos if (bfd_seek (arelt, 0, SEEK_SET))
505 1.1 christos {
506 1.1 christos free (buf);
507 1.1 christos return false;
508 1.1 christos }
509 1.1 christos
510 1.1 christos for (uint32_t i = 0; i < req_blocks; i++)
511 1.1 christos {
512 1.1 christos uint32_t file_block, to_read;
513 1.1 christos
514 1.1 christos if (left == 0)
515 1.1 christos {
516 1.1 christos if (block_map_off == block_size) /* Too many blocks. */
517 1.1 christos {
518 1.1 christos bfd_set_error (bfd_error_invalid_operation);
519 1.1 christos free (buf);
520 1.1 christos return false;
521 1.1 christos }
522 1.1 christos
523 1.1 christos block = pdb_allocate_block (num_blocks, block_size);
524 1.1 christos left = block_size;
525 1.1 christos
526 1.1 christos if (bfd_seek
527 1.1 christos (abfd, (block_map_addr * block_size) + block_map_off,
528 1.1 christos SEEK_SET))
529 1.1 christos {
530 1.1 christos free (buf);
531 1.1 christos return false;
532 1.1 christos }
533 1.1 christos
534 1.1 christos bfd_putl32 (block, tmp);
535 1.1 christos
536 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) !=
537 1.1 christos sizeof (uint32_t))
538 1.1 christos {
539 1.1 christos free (buf);
540 1.1 christos return false;
541 1.1 christos }
542 1.1 christos
543 1.1 christos block_map_off += sizeof (uint32_t);
544 1.1 christos
545 1.1 christos if (bfd_seek (abfd, block * block_size, SEEK_SET))
546 1.1 christos {
547 1.1 christos free (buf);
548 1.1 christos return false;
549 1.1 christos }
550 1.1 christos }
551 1.1 christos
552 1.1 christos /* Allocate block and write number into directory. */
553 1.1 christos
554 1.1 christos file_block = pdb_allocate_block (num_blocks, block_size);
555 1.1 christos
556 1.1 christos bfd_putl32 (file_block, tmp);
557 1.1 christos
558 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
559 1.1 christos {
560 1.1 christos free (buf);
561 1.1 christos return false;
562 1.1 christos }
563 1.1 christos
564 1.1 christos left -= sizeof (uint32_t);
565 1.1 christos
566 1.1 christos /* Read file contents into buffer. */
567 1.1 christos
568 1.1 christos to_read = size > block_size ? block_size : size;
569 1.1 christos
570 1.1 christos if (bfd_bread (buf, to_read, arelt) != to_read)
571 1.1 christos {
572 1.1 christos free (buf);
573 1.1 christos return false;
574 1.1 christos }
575 1.1 christos
576 1.1 christos size -= to_read;
577 1.1 christos
578 1.1 christos if (to_read < block_size)
579 1.1 christos memset (buf + to_read, 0, block_size - to_read);
580 1.1 christos
581 1.1 christos if (bfd_seek (abfd, file_block * block_size, SEEK_SET))
582 1.1 christos {
583 1.1 christos free (buf);
584 1.1 christos return false;
585 1.1 christos }
586 1.1 christos
587 1.1 christos /* Write file contents into allocated block. */
588 1.1 christos
589 1.1 christos if (bfd_bwrite (buf, block_size, abfd) != block_size)
590 1.1 christos {
591 1.1 christos free (buf);
592 1.1 christos return false;
593 1.1 christos }
594 1.1 christos
595 1.1 christos if (bfd_seek
596 1.1 christos (abfd, (block * block_size) + block_size - left, SEEK_SET))
597 1.1 christos {
598 1.1 christos free (buf);
599 1.1 christos return false;
600 1.1 christos }
601 1.1 christos }
602 1.1 christos
603 1.1 christos arelt = arelt->archive_next;
604 1.1 christos }
605 1.1 christos
606 1.1 christos memset (buf, 0, left);
607 1.1 christos
608 1.1 christos if (bfd_bwrite (buf, left, abfd) != left)
609 1.1 christos {
610 1.1 christos free (buf);
611 1.1 christos return false;
612 1.1 christos }
613 1.1 christos
614 1.1 christos free (buf);
615 1.1 christos
616 1.1 christos return true;
617 1.1 christos }
618 1.1 christos
619 1.1 christos static bool
620 1.1 christos pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks)
621 1.1 christos {
622 1.1 christos char *buf;
623 1.1 christos uint32_t num_intervals = (num_blocks + block_size - 1) / block_size;
624 1.1 christos
625 1.1 christos buf = bfd_malloc (block_size);
626 1.1 christos if (!buf)
627 1.1 christos return false;
628 1.1 christos
629 1.1 christos num_blocks--; /* Superblock not included. */
630 1.1 christos
631 1.1 christos for (uint32_t i = 0; i < num_intervals; i++)
632 1.1 christos {
633 1.1 christos if (bfd_seek (abfd, ((i * block_size) + 1) * block_size, SEEK_SET))
634 1.1 christos {
635 1.1 christos free (buf);
636 1.1 christos return false;
637 1.1 christos }
638 1.1 christos
639 1.1 christos /* All of our blocks are contiguous, making our free block map simple.
640 1.1 christos 0 = used, 1 = free. */
641 1.1 christos
642 1.1 christos if (num_blocks >= 8)
643 1.1 christos memset (buf, 0,
644 1.1 christos (num_blocks / 8) >
645 1.1 christos block_size ? block_size : (num_blocks / 8));
646 1.1 christos
647 1.1 christos if (num_blocks < block_size * 8)
648 1.1 christos {
649 1.1 christos unsigned int off = num_blocks / 8;
650 1.1 christos
651 1.1 christos if (num_blocks % 8)
652 1.1 christos {
653 1.1 christos buf[off] = (1 << (8 - (num_blocks % 8))) - 1;
654 1.1 christos off++;
655 1.1 christos }
656 1.1 christos
657 1.1 christos if (off < block_size)
658 1.1 christos memset (buf + off, 0xff, block_size - off);
659 1.1 christos }
660 1.1 christos
661 1.1 christos if (num_blocks < block_size * 8)
662 1.1 christos num_blocks = 0;
663 1.1 christos else
664 1.1 christos num_blocks -= block_size * 8;
665 1.1 christos
666 1.1 christos if (bfd_bwrite (buf, block_size, abfd) != block_size)
667 1.1 christos return false;
668 1.1 christos }
669 1.1 christos
670 1.1 christos free (buf);
671 1.1 christos
672 1.1 christos return true;
673 1.1 christos }
674 1.1 christos
675 1.1 christos static bool
676 1.1 christos pdb_write_contents (bfd *abfd)
677 1.1 christos {
678 1.1 christos char tmp[sizeof (uint32_t)];
679 1.1 christos const uint32_t block_size = 0x400;
680 1.1 christos uint32_t block_map_addr;
681 1.1 christos uint32_t num_blocks;
682 1.1 christos uint32_t num_files = 0;
683 1.1 christos uint32_t num_directory_bytes = sizeof (uint32_t);
684 1.1 christos bfd *arelt;
685 1.1 christos
686 1.1 christos if (bfd_bwrite (pdb_magic, sizeof (pdb_magic), abfd) != sizeof (pdb_magic))
687 1.1 christos return false;
688 1.1 christos
689 1.1 christos bfd_putl32 (block_size, tmp);
690 1.1 christos
691 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
692 1.1 christos return false;
693 1.1 christos
694 1.1 christos bfd_putl32 (1, tmp); /* Free block map block (always either 1 or 2). */
695 1.1 christos
696 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
697 1.1 christos return false;
698 1.1 christos
699 1.1 christos arelt = abfd->archive_head;
700 1.1 christos
701 1.1 christos while (arelt)
702 1.1 christos {
703 1.1 christos uint32_t blocks_required =
704 1.1 christos (bfd_get_size (arelt) + block_size - 1) / block_size;
705 1.1 christos
706 1.1 christos num_directory_bytes += sizeof (uint32_t); /* Size. */
707 1.1 christos num_directory_bytes += blocks_required * sizeof (uint32_t); /* Blocks. */
708 1.1 christos
709 1.1 christos num_files++;
710 1.1 christos
711 1.1 christos arelt = arelt->archive_next;
712 1.1 christos }
713 1.1 christos
714 1.1 christos /* Superblock plus two bitmap blocks. */
715 1.1 christos num_blocks = 3;
716 1.1 christos
717 1.1 christos /* Skip num_blocks for now. */
718 1.1 christos if (bfd_seek (abfd, sizeof (uint32_t), SEEK_CUR))
719 1.1 christos return false;
720 1.1 christos
721 1.1 christos bfd_putl32 (num_directory_bytes, tmp);
722 1.1 christos
723 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
724 1.1 christos return false;
725 1.1 christos
726 1.1 christos /* Skip unknown uint32_t (always 0?). */
727 1.1 christos if (bfd_seek (abfd, sizeof (uint32_t), SEEK_CUR))
728 1.1 christos return false;
729 1.1 christos
730 1.1 christos block_map_addr = pdb_allocate_block (&num_blocks, block_size);
731 1.1 christos
732 1.1 christos bfd_putl32 (block_map_addr, tmp);
733 1.1 christos
734 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
735 1.1 christos return false;
736 1.1 christos
737 1.1 christos if (!pdb_write_directory
738 1.1 christos (abfd, block_size, num_files, block_map_addr, &num_blocks))
739 1.1 christos return false;
740 1.1 christos
741 1.1 christos if (!pdb_write_bitmap (abfd, block_size, num_blocks))
742 1.1 christos return false;
743 1.1 christos
744 1.1 christos /* Write num_blocks now we know it. */
745 1.1 christos
746 1.1 christos if (bfd_seek
747 1.1 christos (abfd, sizeof (pdb_magic) + sizeof (uint32_t) + sizeof (uint32_t),
748 1.1 christos SEEK_SET))
749 1.1 christos return false;
750 1.1 christos
751 1.1 christos bfd_putl32 (num_blocks, tmp);
752 1.1 christos
753 1.1 christos if (bfd_bwrite (tmp, sizeof (uint32_t), abfd) != sizeof (uint32_t))
754 1.1 christos return false;
755 1.1 christos
756 1.1 christos return true;
757 1.1 christos }
758 1.1 christos
759 1.1 christos #define pdb_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
760 1.1 christos #define pdb_new_section_hook _bfd_generic_new_section_hook
761 1.1 christos #define pdb_get_section_contents _bfd_generic_get_section_contents
762 1.1 christos #define pdb_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
763 1.1 christos #define pdb_close_and_cleanup _bfd_generic_close_and_cleanup
764 1.1 christos
765 1.1 christos #define pdb_slurp_armap _bfd_noarchive_slurp_armap
766 1.1 christos #define pdb_slurp_extended_name_table _bfd_noarchive_slurp_extended_name_table
767 1.1 christos #define pdb_construct_extended_name_table _bfd_noarchive_construct_extended_name_table
768 1.1 christos #define pdb_truncate_arname _bfd_noarchive_truncate_arname
769 1.1 christos #define pdb_write_armap _bfd_noarchive_write_armap
770 1.1 christos #define pdb_read_ar_hdr _bfd_noarchive_read_ar_hdr
771 1.1 christos #define pdb_write_ar_hdr _bfd_noarchive_write_ar_hdr
772 1.1 christos #define pdb_update_armap_timestamp _bfd_noarchive_update_armap_timestamp
773 1.1 christos
774 1.1 christos const bfd_target pdb_vec =
775 1.1 christos {
776 1.1 christos "pdb",
777 1.1 christos bfd_target_unknown_flavour,
778 1.1 christos BFD_ENDIAN_LITTLE, /* target byte order */
779 1.1 christos BFD_ENDIAN_LITTLE, /* target headers byte order */
780 1.1 christos 0, /* object flags */
781 1.1 christos 0, /* section flags */
782 1.1 christos 0, /* leading underscore */
783 1.1 christos ' ', /* ar_pad_char */
784 1.1 christos 16, /* ar_max_namelen */
785 1.1 christos 0, /* match priority. */
786 1.1 christos TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */
787 1.1 christos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
788 1.1 christos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
789 1.1 christos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Data. */
790 1.1 christos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
791 1.1 christos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
792 1.1 christos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* Hdrs. */
793 1.1 christos
794 1.1 christos { /* bfd_check_format */
795 1.1 christos _bfd_dummy_target,
796 1.1 christos _bfd_dummy_target,
797 1.1 christos pdb_archive_p,
798 1.1 christos _bfd_dummy_target
799 1.1 christos },
800 1.1 christos { /* bfd_set_format */
801 1.1 christos _bfd_bool_bfd_false_error,
802 1.1 christos _bfd_bool_bfd_false_error,
803 1.1 christos _bfd_bool_bfd_true,
804 1.1 christos _bfd_bool_bfd_false_error
805 1.1 christos },
806 1.1 christos { /* bfd_write_contents */
807 1.1 christos _bfd_bool_bfd_true,
808 1.1 christos _bfd_bool_bfd_false_error,
809 1.1 christos pdb_write_contents,
810 1.1 christos _bfd_bool_bfd_false_error
811 1.1 christos },
812 1.1 christos
813 1.1 christos BFD_JUMP_TABLE_GENERIC (pdb),
814 1.1 christos BFD_JUMP_TABLE_COPY (_bfd_generic),
815 1.1 christos BFD_JUMP_TABLE_CORE (_bfd_nocore),
816 1.1 christos BFD_JUMP_TABLE_ARCHIVE (pdb),
817 1.1 christos BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
818 1.1 christos BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
819 1.1 christos BFD_JUMP_TABLE_WRITE (_bfd_generic),
820 1.1 christos BFD_JUMP_TABLE_LINK (_bfd_nolink),
821 1.1 christos BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
822 1.1 christos
823 1.1 christos NULL,
824 1.1 christos
825 1.1 christos NULL
826 1.1 christos };
827