| 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; |
| } |
| } |