diff options
author | Mark Harmstone <mark@harmstone.com> | 2024-09-01 17:42:30 +0100 |
---|---|---|
committer | Mark Harmstone <mark@harmstone.com> | 2024-09-04 02:24:37 +0100 |
commit | b281480b26f1f27dc83ad3271fb2eaf9736dc3e0 (patch) | |
tree | b4df41bd8dce821103fa9649810a8f4b5814303c /bfd | |
parent | 6225a4d33a783e2556ab78e8c137654caa3d6dfe (diff) | |
download | gdb-b281480b26f1f27dc83ad3271fb2eaf9736dc3e0.zip gdb-b281480b26f1f27dc83ad3271fb2eaf9736dc3e0.tar.gz gdb-b281480b26f1f27dc83ad3271fb2eaf9736dc3e0.tar.bz2 |
bfd/pdb: fix bitmap generation in pdb_write_bitmap
MSVC 2022 is more pedantic than MSVC 2019 when it comes to loading PDB
files in readonly mode, and was rejecting PDB files generated by binutils
because of their invalid free-space bitmaps. It's unknown what would
have happened if you tried to use MS tools to modify a PDB created by
binutils, but it probably would have led to a corrupted file.
This patch fixes pdb_write_bitmap so we generate files that MSVC will accept.
Specifically there were three things we were doing wrong:
- We weren't including the superblock (block 0)
- We were setting bits in bytes backwards (MSB to LSB, rather than LSB to MSB)
- We should have been marking the contents of stream 0 as free. This is
because, as the comment says, it's intended to be used for the
directory for the previous write, to allow atomic updates.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/pdb.c | 57 |
1 files changed, 48 insertions, 9 deletions
@@ -412,7 +412,8 @@ pdb_allocate_block (uint32_t *num_blocks, uint32_t block_size) static bool pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, - uint32_t block_map_addr, uint32_t * num_blocks) + uint32_t block_map_addr, uint32_t * num_blocks, + uint32_t *stream0_start) { char tmp[sizeof (uint32_t)]; uint32_t block, left, block_map_off; @@ -561,6 +562,9 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, return false; } + if (arelt == abfd->archive_head && i == 0) + *stream0_start = file_block; + left -= sizeof (uint32_t); /* Read file contents into buffer. */ @@ -617,7 +621,8 @@ pdb_write_directory (bfd *abfd, uint32_t block_size, uint32_t num_files, } static bool -pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) +pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks, + uint32_t stream0_start) { char *buf; uint32_t num_intervals = (num_blocks + block_size - 1) / block_size; @@ -626,8 +631,6 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (!buf) return false; - num_blocks--; /* Superblock not included. */ - for (uint32_t i = 0; i < num_intervals; i++) { if (bfd_seek (abfd, ((i * block_size) + 1) * block_size, SEEK_SET)) @@ -636,8 +639,8 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) return false; } - /* All of our blocks are contiguous, making our free block map simple. - 0 = used, 1 = free. */ + /* All of our blocks are contiguous, making our free block map + relatively simple. 0 = used, 1 = free. */ if (num_blocks >= 8) memset (buf, 0, @@ -650,7 +653,7 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) if (num_blocks % 8) { - buf[off] = (1 << (8 - (num_blocks % 8))) - 1; + buf[off] = 256 - (1 << (num_blocks % 8)); off++; } @@ -658,6 +661,40 @@ pdb_write_bitmap (bfd *abfd, uint32_t block_size, uint32_t num_blocks) memset (buf + off, 0xff, block_size - off); } + /* Mark the blocks allocated to stream 0 as free. This is because stream + 0 is intended to be used for the previous MSF directory, to allow + atomic updates. This doesn't apply to us, as we rewrite the whole + file whenever any change is made. */ + + if (i == 0 && abfd->archive_head) + { + bfd *arelt = abfd->archive_head; + uint32_t stream0_blocks = + (bfd_get_size (arelt) + block_size - 1) / block_size; + + if (stream0_start % 8) + { + unsigned int high_bit; + + high_bit = (stream0_start % 8) + stream0_blocks; + if (high_bit > 8) + high_bit = 8; + + buf[stream0_start / 8] |= + (1 << high_bit) - (1 << (stream0_start % 8)); + + stream0_blocks -= high_bit - (stream0_start % 8); + stream0_start += high_bit - (stream0_start % 8); + } + + memset (buf + (stream0_start / 8), 0xff, stream0_blocks / 8); + stream0_start += stream0_blocks / 8; + stream0_blocks %= 8; + + if (stream0_blocks > 0) + buf[stream0_start / 8] |= (1 << stream0_blocks) - 1; + } + if (num_blocks < block_size * 8) num_blocks = 0; else @@ -681,6 +718,7 @@ pdb_write_contents (bfd *abfd) uint32_t num_blocks; uint32_t num_files = 0; uint32_t num_directory_bytes = sizeof (uint32_t); + uint32_t stream0_start; bfd *arelt; if (bfd_write (pdb_magic, sizeof (pdb_magic), abfd) != sizeof (pdb_magic)) @@ -735,10 +773,11 @@ pdb_write_contents (bfd *abfd) return false; if (!pdb_write_directory - (abfd, block_size, num_files, block_map_addr, &num_blocks)) + (abfd, block_size, num_files, block_map_addr, &num_blocks, + &stream0_start)) return false; - if (!pdb_write_bitmap (abfd, block_size, num_blocks)) + if (!pdb_write_bitmap (abfd, block_size, num_blocks, stream0_start)) return false; /* Write num_blocks now we know it. */ |