blob: 4b969c00d9faa1ffb09ab343fd8e6aec0dd01020 [file] [log] [blame]
Patch-by: Peter Alfredsen <loki_val@gentoo.org>
Mega patch, containing in no particular order:
support for including empty directories in the output:
https://bugzilla.redhat.com/show_bug.cgi?id=444310
A bunch of warning fixes.
DWARF3-support:
https://bugzilla.redhat.com/show_bug.cgi?id=505774
Most of this was pulled from rpm5.org
We have factored out the support for the -i command line switch, since
that would require pulling in another dependency (Beecrypt)
--- debugedit.c.old 2009-10-20 16:48:31.000000000 +0200
+++ debugedit.c 2009-10-20 16:58:45.000000000 +0200
@@ -1,6 +1,6 @@
-/* Copyright (C) 2001, 2002, 2003, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2005, 2007 Red Hat, Inc.
Written by Alexander Larsson <alexl@redhat.com>, 2002
Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -83,10 +83,11 @@
static uint_16 (*do_read_16) (unsigned char *ptr);
static uint_32 (*do_read_32) (unsigned char *ptr);
static void (*write_32) (unsigned char *ptr, GElf_Addr val);
static int ptr_size;
+static int cu_version;
static inline uint_16
buf_read_ule16 (unsigned char *data)
{
return data[0] | (data[1] << 8);
@@ -122,11 +123,11 @@
data = NULL;
while ((data = elf_rawdata (scn, data)) != NULL)
{
if (data->d_buf
&& offset >= data->d_off
- && offset < data->d_off + data->d_size)
+ && offset < data->d_off + (off_t)data->d_size)
return (const char *) data->d_buf + (offset - data->d_off);
}
}
return NULL;
@@ -208,20 +209,22 @@
#define DEBUG_INFO 0
#define DEBUG_ABBREV 1
#define DEBUG_LINE 2
#define DEBUG_ARANGES 3
#define DEBUG_PUBNAMES 4
-#define DEBUG_MACINFO 5
-#define DEBUG_LOC 6
-#define DEBUG_STR 7
-#define DEBUG_FRAME 8
-#define DEBUG_RANGES 9
+#define DEBUG_PUBTYPES 5
+#define DEBUG_MACINFO 6
+#define DEBUG_LOC 7
+#define DEBUG_STR 8
+#define DEBUG_FRAME 9
+#define DEBUG_RANGES 10
{ ".debug_info", NULL, NULL, 0, 0, 0 },
{ ".debug_abbrev", NULL, NULL, 0, 0, 0 },
{ ".debug_line", NULL, NULL, 0, 0, 0 },
{ ".debug_aranges", NULL, NULL, 0, 0, 0 },
{ ".debug_pubnames", NULL, NULL, 0, 0, 0 },
+ { ".debug_pubtypes", NULL, NULL, 0, 0, 0 },
{ ".debug_macinfo", NULL, NULL, 0, 0, 0 },
{ ".debug_loc", NULL, NULL, 0, 0, 0 },
{ ".debug_str", NULL, NULL, 0, 0, 0 },
{ ".debug_frame", NULL, NULL, 0, 0, 0 },
{ ".debug_ranges", NULL, NULL, 0, 0, 0 },
@@ -297,11 +300,11 @@
free (t);
goto no_memory;
}
if (*slot != NULL)
{
- error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
+ error (0, 0, "%s: Duplicate DWARF abbreviation %d", dso->filename,
t->entry);
free (t);
htab_delete (h);
return NULL;
}
@@ -317,21 +320,21 @@
goto no_memory;
}
form = read_uleb128 (ptr);
if (form == 2 || form > DW_FORM_indirect)
{
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
htab_delete (h);
return NULL;
}
t->attr[t->nattr].attr = attr;
t->attr[t->nattr++].form = form;
}
if (read_uleb128 (ptr) != 0)
{
- error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
+ error (0, 0, "%s: DWARF abbreviation does not end with 2 zeros",
dso->filename);
htab_delete (h);
return NULL;
}
*slot = t;
@@ -369,46 +372,49 @@
/* At this point, we're always at the beginning of a path
segment. */
if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
{
- s ++;
+ s++;
if (*s)
- s++;
- else if (d > droot)
- d--;
+ while (IS_DIR_SEPARATOR (*s))
+ ++s;
}
else if (s[0] == '.' && s[1] == '.'
&& (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
{
- char *pre = d-1; /* includes slash */
+ char *pre = d - 1; /* includes slash */
while (droot < pre && IS_DIR_SEPARATOR (*pre))
pre--;
if (droot <= pre && ! IS_DIR_SEPARATOR (*pre))
{
- d = pre;
- while (droot < d && ! IS_DIR_SEPARATOR (*d))
- d--;
- /* d now points to the slash */
- if (droot < d)
- d++;
- s += 2;
- if (*s)
- s++;
- else if (d > droot)
- d--;
+ while (droot < pre && ! IS_DIR_SEPARATOR (*pre))
+ pre--;
+ /* pre now points to the slash */
+ if (droot < pre)
+ pre++;
+ if (pre + 3 == d && pre[0] == '.' && pre[1] == '.')
+ {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+ else
+ {
+ d = pre;
+ s += 2;
+ if (*s)
+ while (IS_DIR_SEPARATOR (*s))
+ s++;
+ }
}
else
{
*d++ = *s++;
*d++ = *s++;
- if (*s)
- *d++ = *s++;
}
}
-
else
{
while (*s && ! IS_DIR_SEPARATOR (*s))
*d++ = *s++;
}
@@ -431,12 +437,12 @@
static int
has_prefix (const char *str,
const char *prefix)
{
- int str_len;
- int prefix_len;
+ size_t str_len;
+ size_t prefix_len;
str_len = strlen (str);
prefix_len = strlen (prefix);
if (str_len < prefix_len)
@@ -476,11 +482,11 @@
dso->filename);
return 1;
}
value = read_16 (ptr);
- if (value != 2)
+ if (value != 2 && value != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
value);
return 1;
}
@@ -499,43 +505,43 @@
/* dir table: */
value = 1;
while (*ptr != 0)
{
- ptr = strchr (ptr, 0) + 1;
+ ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
++value;
}
dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
- dirt[0] = ".";
+ dirt[0] = (unsigned char *) ".";
dirt_cnt = 1;
ptr = dir;
while (*ptr != 0)
{
dirt[dirt_cnt++] = ptr;
- ptr = strchr (ptr, 0) + 1;
+ ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
}
ptr++;
/* file table: */
while (*ptr != 0)
{
char *s, *file;
size_t file_len, dir_len;
- file = ptr;
- ptr = strchr (ptr, 0) + 1;
+ file = (char *) ptr;
+ ptr = (unsigned char *) strchr ((char *)ptr, 0) + 1;
value = read_uleb128 (ptr);
if (value >= dirt_cnt)
{
error (0, 0, "%s: Wrong directory table index %u",
dso->filename, value);
return 1;
}
file_len = strlen (file);
- dir_len = strlen (dirt[value]);
+ dir_len = strlen ((char *)dirt[value]);
s = malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1);
if (s == NULL)
{
error (0, ENOMEM, "%s: Reading file table", dso->filename);
return 1;
@@ -552,34 +558,38 @@
s[dir_len] = '/';
memcpy (s + dir_len + 1, file, file_len + 1);
}
else
{
- memcpy (s, comp_dir, comp_dir_len);
- s[comp_dir_len] = '/';
- memcpy (s + comp_dir_len + 1, dirt[value], dir_len);
- s[comp_dir_len + 1 + dir_len] = '/';
- memcpy (s + comp_dir_len + 1 + dir_len + 1, file, file_len + 1);
+ char *p = s;
+ if (comp_dir_len != 0)
+ {
+ memcpy (s, comp_dir, comp_dir_len);
+ s[comp_dir_len] = '/';
+ p += comp_dir_len + 1;
+ }
+ memcpy (p, dirt[value], dir_len);
+ p[dir_len] = '/';
+ memcpy (p + dir_len + 1, file, file_len + 1);
}
canonicalize_path (s, s);
- if (base_dir == NULL ||
- has_prefix (s, base_dir))
+ if (list_file_fd != -1)
{
- char *p;
- size_t size;
- ssize_t ret;
- if (base_dir)
- p = s + strlen (base_dir);
- else
+ char *p = NULL;
+ if (base_dir == NULL)
p = s;
-
- if (list_file_fd != -1)
+ else if (has_prefix (s, base_dir))
+ p = s + strlen (base_dir);
+ else if (has_prefix (s, dest_dir))
+ p = s + strlen (dest_dir);
+
+ if (p)
{
- size = strlen (p) + 1;
+ size_t size = strlen (p) + 1;
while (size > 0)
{
- ret = write (list_file_fd, p, size);
+ ssize_t ret = write (list_file_fd, p, size);
if (ret == -1)
break;
size -= ret;
p += ret;
}
@@ -610,26 +620,26 @@
}
else
ptr = srcptr = dir;
while (*srcptr != 0)
{
- size_t len = strlen (srcptr) + 1;
+ size_t len = strlen ((char *)srcptr) + 1;
const unsigned char *readptr = srcptr;
- if (*srcptr == '/' && has_prefix (srcptr, base_dir))
+ if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir))
{
if (dest_len < base_len)
++abs_dir_cnt;
memcpy (ptr, dest_dir, dest_len);
ptr += dest_len;
readptr += base_len;
}
srcptr += len;
shrank += srcptr - readptr;
- canonicalize_path (readptr, ptr);
- len = strlen (ptr) + 1;
+ canonicalize_path ((char *)readptr, (char *)ptr);
+ len = strlen ((char *)ptr) + 1;
shrank -= len;
ptr += len;
elf_flagdata (debug_sections[DEBUG_STR].elf_data,
ELF_C_SET, ELF_F_DIRTY);
@@ -638,13 +648,16 @@
if (shrank > 0)
{
if (--shrank == 0)
error (EXIT_FAILURE, 0,
"canonicalization unexpectedly shrank by one character");
- memset (ptr, 'X', shrank);
- ptr += shrank;
- *ptr++ = '\0';
+ else
+ {
+ memset (ptr, 'X', shrank);
+ ptr += shrank;
+ *ptr++ = '\0';
+ }
}
if (abs_dir_cnt + abs_file_cnt != 0)
{
size_t len = (abs_dir_cnt + abs_file_cnt) * (base_len - dest_len);
@@ -658,13 +671,13 @@
*ptr++ = '\0';
++srcptr;
while (*srcptr != 0)
{
- size_t len = strlen (srcptr) + 1;
+ size_t len = strlen ((char *)srcptr) + 1;
- if (*srcptr == '/' && has_prefix (srcptr, base_dir))
+ if (*srcptr == '/' && has_prefix ((char *)srcptr, base_dir))
{
memcpy (ptr, dest_dir, dest_len);
if (dest_len < base_len)
{
memmove (ptr + dest_len, srcptr + base_len,
@@ -698,20 +711,20 @@
edit_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t, int phase)
{
int i;
uint_32 list_offs;
int found_list_offs;
- unsigned char *comp_dir;
+ char *comp_dir;
comp_dir = NULL;
list_offs = 0;
found_list_offs = 0;
for (i = 0; i < t->nattr; ++i)
{
uint_32 form = t->attr[i].form;
- uint_32 len = 0;
- int base_len, dest_len;
+ size_t len = 0;
+ size_t base_len, dest_len;
while (1)
{
if (t->attr[i].attr == DW_AT_stmt_list)
@@ -721,70 +734,70 @@
list_offs = do_read_32_relocated (ptr);
found_list_offs = 1;
}
}
- else if (t->attr[i].attr == DW_AT_comp_dir)
- {
- if (form == DW_FORM_string)
- {
+ if (t->attr[i].attr == DW_AT_comp_dir)
+ {
+ if ( form == DW_FORM_string )
+ {
free (comp_dir);
- comp_dir = strdup (ptr);
-
- if (phase == 1 && dest_dir && has_prefix (ptr, base_dir))
- {
+ comp_dir = strdup ((char *)ptr);
+
+ if (phase == 1 && dest_dir && has_prefix ((char *)ptr, base_dir))
+ {
base_len = strlen (base_dir);
dest_len = strlen (dest_dir);
-
+
memcpy (ptr, dest_dir, dest_len);
if (dest_len < base_len)
- {
- memset (ptr + dest_len, '/',
- base_len - dest_len);
-
- }
+ {
+ memset(ptr + dest_len, '/',
+ base_len - dest_len);
+
+ }
elf_flagdata (debug_sections[DEBUG_INFO].elf_data,
ELF_C_SET, ELF_F_DIRTY);
- }
- }
+ }
+ }
+
+ else if (form == DW_FORM_strp &&
+ debug_sections[DEBUG_STR].data)
+ {
+ char *dir;
- else if (form == DW_FORM_strp &&
- debug_sections[DEBUG_STR].data)
- {
- char *dir;
-
- dir = debug_sections[DEBUG_STR].data
- + do_read_32_relocated (ptr);
- free (comp_dir);
- comp_dir = strdup (dir);
+ dir = (char *) debug_sections[DEBUG_STR].data
+ + do_read_32_relocated (ptr);
- if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
- {
- base_len = strlen (base_dir);
- dest_len = strlen (dest_dir);
-
- memcpy (dir, dest_dir, dest_len);
- if (dest_len < base_len)
- {
- memmove (dir + dest_len, dir + base_len,
- strlen (dir + base_len) + 1);
- }
- elf_flagdata (debug_sections[DEBUG_STR].elf_data,
- ELF_C_SET, ELF_F_DIRTY);
- }
- }
- }
+ free (comp_dir);
+ comp_dir = strdup (dir);
+ if (phase == 1 && dest_dir && has_prefix (dir, base_dir))
+ {
+ base_len = strlen (base_dir);
+ dest_len = strlen (dest_dir);
+
+ memcpy (dir, dest_dir, dest_len);
+ if (dest_len < base_len)
+ {
+ memmove (dir + dest_len, dir + base_len,
+ strlen (dir + base_len) + 1);
+ }
+ elf_flagdata (debug_sections[DEBUG_STR].elf_data,
+ ELF_C_SET, ELF_F_DIRTY);
+ }
+ }
+ }
else if ((t->tag == DW_TAG_compile_unit
|| t->tag == DW_TAG_partial_unit)
&& t->attr[i].attr == DW_AT_name
&& form == DW_FORM_strp
&& debug_sections[DEBUG_STR].data)
{
char *name;
- name = debug_sections[DEBUG_STR].data
+ name = (char *) debug_sections[DEBUG_STR].data
+ do_read_32_relocated (ptr);
if (*name == '/' && comp_dir == NULL)
{
char *enddir = strrchr (name, '/');
@@ -814,10 +827,16 @@
}
}
switch (form)
{
+ case DW_FORM_ref_addr:
+ if (cu_version == 2)
+ ptr += ptr_size;
+ else
+ ptr += 4;
+ break;
case DW_FORM_addr:
ptr += ptr_size;
break;
case DW_FORM_ref1:
case DW_FORM_flag:
@@ -839,16 +858,15 @@
case DW_FORM_sdata:
case DW_FORM_ref_udata:
case DW_FORM_udata:
read_uleb128 (ptr);
break;
- case DW_FORM_ref_addr:
case DW_FORM_strp:
ptr += 4;
break;
case DW_FORM_string:
- ptr = strchr (ptr, '\0') + 1;
+ ptr = (unsigned char *) strchr ((char *)ptr, '\0') + 1;
break;
case DW_FORM_indirect:
form = read_uleb128 (ptr);
continue;
case DW_FORM_block1:
@@ -866,21 +884,49 @@
len = read_uleb128 (ptr);
form = DW_FORM_block1;
assert (len < UINT_MAX);
break;
default:
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename,
form);
return NULL;
}
if (form == DW_FORM_block1)
ptr += len;
break;
}
}
+
+ /* Ensure the CU current directory will exist even if only empty. Source
+ filenames possibly located in its parent directories refer relatively to
+ it and the debugger (GDB) cannot safely optimize out the missing
+ CU current dir subdirectories. */
+ if (comp_dir && list_file_fd != -1)
+ {
+ char *p;
+ size_t size;
+
+ if (base_dir && has_prefix (comp_dir, base_dir))
+ p = comp_dir + strlen (base_dir);
+ else if (dest_dir && has_prefix (comp_dir, dest_dir))
+ p = comp_dir + strlen (dest_dir);
+ else
+ p = comp_dir;
+
+ size = strlen (p) + 1;
+ while (size > 0)
+ {
+ ssize_t ret = write (list_file_fd, p, size);
+ if (ret == -1)
+ break;
+ size -= ret;
+ p += ret;
+ }
+ }
+
if (found_list_offs && comp_dir)
edit_dwarf2_line (dso, list_offs, comp_dir, phase);
free (comp_dir);
@@ -1068,11 +1114,11 @@
if (rtype != R_386_32)
goto fail;
break;
case EM_PPC:
case EM_PPC64:
- if (rtype != R_PPC_ADDR32 || rtype != R_PPC_UADDR32)
+ if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
goto fail;
break;
case EM_S390:
if (rtype != R_390_32)
goto fail;
@@ -1135,42 +1181,42 @@
{
error (0, 0, "%s: .debug_info too small", dso->filename);
return 1;
}
- value = read_16 (ptr);
- if (value != 2)
+ cu_version = read_16 (ptr);
+ if (cu_version != 2 && cu_version != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
- value);
+ cu_version);
return 1;
}
value = read_32_relocated (ptr);
if (value >= debug_sections[DEBUG_ABBREV].size)
{
if (debug_sections[DEBUG_ABBREV].data == NULL)
error (0, 0, "%s: .debug_abbrev not present", dso->filename);
else
- error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
+ error (0, 0, "%s: DWARF CU abbrev offset too large",
dso->filename);
return 1;
}
if (ptr_size == 0)
{
ptr_size = read_1 (ptr);
if (ptr_size != 4 && ptr_size != 8)
{
- error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
dso->filename, ptr_size);
return 1;
}
}
else if (read_1 (ptr) != ptr_size)
{
- error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
dso->filename);
return 1;
}
abbrev = read_abbrev (dso,
@@ -1184,11 +1230,11 @@
if (tag.entry == 0)
continue;
t = htab_find_with_hash (abbrev, &tag, tag.entry);
if (t == NULL)
{
- error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
+ error (0, 0, "%s: Could not find DWARF abbreviation %d",
dso->filename, tag.entry);
htab_delete (abbrev);
return 1;
}
@@ -1289,11 +1335,10 @@
if (fd != -1)
close (fd);
return NULL;
}
-
int
main (int argc, char *argv[])
{
DSO *dso;
int fd, i;
@@ -1301,13 +1346,12 @@
poptContext optCon; /* context for parsing command-line options */
int nextopt;
const char **args;
struct stat stat_buf;
char *p;
-
- optCon = poptGetContext("debugedit", argc, (const char **)argv,
- optionsTable, 0);
+
+ optCon = poptGetContext("debugedit", argc, (const char **)argv, optionsTable, 0);
while ((nextopt = poptGetNextOpt (optCon)) > 0 || nextopt == POPT_ERROR_BADOPT)
/* do nothing */ ;
if (nextopt != -1)
@@ -1404,11 +1448,11 @@
if (strcmp (name, ".stab") == 0)
edit_stabs (dso, i);
#endif
if (strcmp (name, ".debug_info") == 0)
edit_dwarf2 (dso);
-
+
break;
default:
break;
}
}