aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorMark Harmstone <mark@harmstone.com>2024-09-01 17:42:30 +0100
committerMark Harmstone <mark@harmstone.com>2024-09-04 02:24:37 +0100
commitb281480b26f1f27dc83ad3271fb2eaf9736dc3e0 (patch)
treeb4df41bd8dce821103fa9649810a8f4b5814303c /bfd
parent6225a4d33a783e2556ab78e8c137654caa3d6dfe (diff)
downloadgdb-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.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/bfd/pdb.c b/bfd/pdb.c
index b0455b0..c4c5287 100644
--- a/bfd/pdb.c
+++ b/bfd/pdb.c
@@ -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. */