aboutsummaryrefslogtreecommitdiff
path: root/ld/pdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/pdb.c')
-rw-r--r--ld/pdb.c107
1 files changed, 104 insertions, 3 deletions
diff --git a/ld/pdb.c b/ld/pdb.c
index 88639d5..82c57f9 100644
--- a/ld/pdb.c
+++ b/ld/pdb.c
@@ -161,6 +161,9 @@ static const uint32_t crc_table[] =
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+static bool remap_type (void *data, struct type_entry **map,
+ uint32_t type_num, uint32_t num_types);
+
/* Add a new stream to the PDB archive, and return its BFD. */
static bfd *
add_stream (bfd *pdb, const char *name, uint16_t *stream_num)
@@ -175,7 +178,7 @@ add_stream (bfd *pdb, const char *name, uint16_t *stream_num)
if (!bfd_make_writable (stream))
{
bfd_close (stream);
- return false;
+ return NULL;
}
if (!pdb->archive_head)
@@ -872,7 +875,7 @@ add_globals_ref (struct globals *glob, bfd *sym_rec_stream, const char *name,
*slot = xmalloc (offsetof (struct global, data) + len);
- hash = crc32 ((const uint8_t *) name, name_len);
+ hash = calc_hash (name, name_len);
hash %= NUM_GLOBALS_HASH_BUCKETS;
g = *slot;
@@ -1836,6 +1839,76 @@ calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size)
return true;
}
+/* Parse the DEBUG_S_INLINEELINES data, which records the line numbers that
+ correspond to inlined functions. This is similar to DEBUG_S_LINES (see
+ handle_debugs_section), but rather than just copying we also need to remap
+ the numbers of the referenced LF_FUNC_ID types. */
+
+static bool
+parse_inlinee_lines (uint8_t *data, uint32_t size, uint8_t **bufptr,
+ struct type_entry **map, uint32_t num_types)
+{
+ uint32_t version;
+ uint8_t *ptr;
+ unsigned int num_entries;
+
+ bfd_putl32 (DEBUG_S_INLINEELINES, *bufptr);
+ *bufptr += sizeof (uint32_t);
+
+ bfd_putl32 (size, *bufptr);
+ *bufptr += sizeof (uint32_t);
+
+ /* The inlinee lines data consists of a version uint32_t (0), followed by an
+ array of struct inlinee_source_line:
+
+ struct inlinee_source_line
+ {
+ uint32_t function_id;
+ uint32_t file_id;
+ uint32_t line_no;
+ };
+
+ (see InlineeSourceLine in cvinfo.h)
+
+ We're only interested here in the function_id, as we need to remap its
+ type number.
+ */
+
+ if (size < sizeof (uint32_t))
+ {
+ einfo (_("%P: warning: truncated DEBUG_S_INLINEELINES data\n"));
+ return false;
+ }
+
+ version = bfd_getl32 (data + sizeof (uint32_t) + sizeof (uint32_t));
+ if (version != CV_INLINEE_SOURCE_LINE_SIGNATURE)
+ {
+ einfo (_("%P: warning: unexpected DEBUG_S_INLINEELINES version %u\n"),
+ version);
+ return false;
+ }
+
+ memcpy (*bufptr, data, size);
+ ptr = *bufptr + sizeof (uint32_t);
+ *bufptr += size;
+
+ num_entries = (size - sizeof (uint32_t)) / (3 * sizeof (uint32_t));
+
+ for (unsigned int i = 0; i < num_entries; i++)
+ {
+ uint32_t func_id;
+
+ func_id = bfd_getl32 (ptr);
+
+ if (!remap_type (ptr, map, func_id, num_types))
+ return false;
+
+ ptr += 3 * sizeof (uint32_t);
+ }
+
+ return true;
+}
+
/* Parse the .debug$S section within an object file. */
static bool
handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
@@ -1951,6 +2024,7 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
switch (type)
{
case DEBUG_S_FILECHKSMS:
+ case DEBUG_S_INLINEELINES:
c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size;
if (c13_size % sizeof (uint32_t))
@@ -2088,6 +2162,16 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
}
break;
+
+ case DEBUG_S_INLINEELINES:
+ if (!parse_inlinee_lines (data + off, size, &bufptr, map, num_types))
+ {
+ free (data);
+ free (symbuf);
+ return false;
+ }
+
+ break;
}
off += size;
@@ -2375,6 +2459,7 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
case LF_POINTER:
{
struct lf_pointer *ptr = (struct lf_pointer *) data;
+ uint32_t attributes;
if (size < offsetof (struct lf_pointer, attributes))
{
@@ -2386,6 +2471,22 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
if (!remap_type (&ptr->base_type, map, type_num, num_types))
return false;
+ attributes = bfd_getl32 (&ptr->attributes);
+
+ if ((attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMEM
+ || (attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMFUNC)
+ {
+ if (size < offsetof (struct lf_pointer, ptr_to_mem_type))
+ {
+ einfo (_("%P: warning: truncated CodeView type record"
+ " LF_POINTER\n"));
+ return false;
+ }
+
+ if (!remap_type (&ptr->containing_class, map, type_num, num_types))
+ return false;
+ }
+
break;
}
@@ -3582,7 +3683,7 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types,
size = bfd_getl16 (data + off);
off += sizeof (uint16_t);
- if (size + off > s->size || size <= sizeof (uint16_t))
+ if (size + off > s->size || size < sizeof (uint16_t))
{
free (data);
bfd_set_error (bfd_error_bad_value);