Patch-by: Peter Alfredsen 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 , 2002 Based on code by Jakub Jelinek , 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; } }