diff options
Diffstat (limited to 'gdb')
27 files changed, 410 insertions, 425 deletions
diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c index 140fc71..c87e7be 100644 --- a/gdb/ada-varobj.c +++ b/gdb/ada-varobj.c @@ -379,16 +379,14 @@ ada_varobj_get_number_of_children (struct value *parent_value, whose index is CHILD_INDEX: - If CHILD_NAME is not NULL, then a copy of the child's name - is saved in *CHILD_NAME. This copy must be deallocated - with xfree after use. + is saved in *CHILD_NAME. - If CHILD_VALUE is not NULL, then save the child's value in *CHILD_VALUE. Same thing for the child's type with CHILD_TYPE if not NULL. - If CHILD_PATH_EXPR is not NULL, then compute the child's - path expression. The resulting string must be deallocated - after use with xfree. + path expression. Computing the child's path expression requires the PARENT_PATH_EXPR to be non-NULL. Otherwise, PARENT_PATH_EXPR may be null if @@ -805,9 +803,7 @@ ada_varobj_get_type_of_child (struct value *parent_value, } /* Return a string that contains the image of the given VALUE, using - the print options OPTS as the options for formatting the result. - - The resulting string must be deallocated after use with xfree. */ + the print options OPTS as the options for formatting the result. */ static std::string ada_varobj_get_value_image (struct value *value, @@ -825,9 +821,7 @@ ada_varobj_get_value_image (struct value *value, in the array inside square brackets, but there are situations where it's useful to add more info. - OPTS are the print options used when formatting the result. - - The result should be deallocated after use using xfree. */ + OPTS are the print options used when formatting the result. */ static std::string ada_varobj_get_value_of_array_variable (struct value *value, diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 7e13ef8..9a5021f 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -833,7 +833,7 @@ echo_command (const char *text, int from_tty) gdb_printf ("%c", c); } - gdb_stdout->reset_style (); + gdb_stdout->emit_style_escape (ui_file_style ()); /* Force this output to appear now. */ gdb_flush (gdb_stdout); diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 50342bb..80f4c14 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -4554,8 +4554,8 @@ registered. The help text for the new command is taken from the Python documentation string for the command's class, if there is one. If no -documentation string is provided, the default value ``This command is -not documented.'' is used. +documentation string is provided, the default value @samp{This command +is not documented.} is used. @end defun @cindex don't repeat Python command diff --git a/gdb/dwarf2/comp-unit-head.c b/gdb/dwarf2/comp-unit-head.c index 8ec8897..a35d664 100644 --- a/gdb/dwarf2/comp-unit-head.c +++ b/gdb/dwarf2/comp-unit-head.c @@ -26,7 +26,6 @@ #include "dwarf2/comp-unit-head.h" #include "dwarf2/leb.h" -#include "dwarf2/read.h" #include "dwarf2/section.h" #include "dwarf2/stringify.h" #include "dwarf2/error.h" @@ -149,15 +148,13 @@ read_comp_unit_head (struct comp_unit_head *cu_header, Perform various error checking on the header. */ static void -error_check_comp_unit_head (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section) +error_check_comp_unit_head (comp_unit_head *header, + dwarf2_section_info *section, + dwarf2_section_info *abbrev_section) { const char *filename = section->get_file_name (); - if (to_underlying (header->abbrev_sect_off) - >= abbrev_section->get_size (per_objfile->objfile)) + if (to_underlying (header->abbrev_sect_off) >= abbrev_section->size) error (_(DWARF_ERROR_PREFIX "bad offset (%s) in compilation unit header " "(offset %s + 6) [in module %s]"), @@ -179,12 +176,10 @@ error_check_comp_unit_head (dwarf2_per_objfile *per_objfile, /* See comp-unit-head.h. */ const gdb_byte * -read_and_check_comp_unit_head (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section, - const gdb_byte *info_ptr, - rcuh_kind section_kind) +read_and_check_comp_unit_head (comp_unit_head *header, + dwarf2_section_info *section, + dwarf2_section_info *abbrev_section, + const gdb_byte *info_ptr, rcuh_kind section_kind) { const gdb_byte *beg_of_comp_unit = info_ptr; @@ -194,7 +189,7 @@ read_and_check_comp_unit_head (dwarf2_per_objfile *per_objfile, header->first_die_cu_offset = (cu_offset) (info_ptr - beg_of_comp_unit); - error_check_comp_unit_head (per_objfile, header, section, abbrev_section); + error_check_comp_unit_head (header, section, abbrev_section); return info_ptr; } diff --git a/gdb/dwarf2/comp-unit-head.h b/gdb/dwarf2/comp-unit-head.h index 5134893..ea09153 100644 --- a/gdb/dwarf2/comp-unit-head.h +++ b/gdb/dwarf2/comp-unit-head.h @@ -129,11 +129,8 @@ extern const gdb_byte *read_comp_unit_head The contents of the header are stored in HEADER. The result is a pointer to the start of the first DIE. */ extern const gdb_byte *read_and_check_comp_unit_head - (dwarf2_per_objfile *per_objfile, - struct comp_unit_head *header, - struct dwarf2_section_info *section, - struct dwarf2_section_info *abbrev_section, - const gdb_byte *info_ptr, + (comp_unit_head *header, dwarf2_section_info *section, + dwarf2_section_info *abbrev_section, const gdb_byte *info_ptr, rcuh_kind section_kind); #endif /* GDB_DWARF2_COMP_UNIT_HEAD_H */ diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 794c397..55cf02f 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -1039,14 +1039,7 @@ static struct dwo_unit *lookup_dwo_unit_in_dwp (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, const char *comp_dir, ULONGEST signature, int is_debug_types); -static struct dwp_file *get_dwp_file (dwarf2_per_objfile *per_objfile); - -static struct dwo_unit *lookup_dwo_comp_unit - (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature); - -static struct dwo_unit *lookup_dwo_type_unit - (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir); +static void open_and_init_dwp_file (dwarf2_per_objfile *per_objfile); static void queue_and_load_all_dwo_tus (dwarf2_cu *cu); @@ -1295,6 +1288,15 @@ dwarf2_has_info (struct objfile *objfile, { warning (_("%s"), err.what ()); } + + try + { + open_and_init_dwp_file (per_objfile); + } + catch (const gdb_exception_error &err) + { + warning (_("%s"), err.what ()); + } } return has_info; @@ -1632,7 +1634,7 @@ dw2_do_instantiate_symtab (dwarf2_per_cu *per_cu, && per_objfile->per_bfd->index_table != NULL && !per_objfile->per_bfd->index_table->version_check () /* DWP files aren't supported yet. */ - && get_dwp_file (per_objfile) == NULL) + && per_objfile->per_bfd->dwp_file == nullptr) queue_and_load_all_dwo_tus (cu); } @@ -2387,12 +2389,12 @@ read_abbrev_offset (dwarf2_per_objfile *per_objfile, and fill them into DWO_FILE's type unit hash table. It will process only type units, therefore DW_UT_type. */ -static void -create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, - dwo_file *dwo_file, dwarf2_section_info *section, - rcuh_kind section_kind) +void +cutu_reader::create_dwo_debug_type_hash_table (dwarf2_per_bfd *per_bfd, + dwo_file *dwo_file, + dwarf2_section_info *section, + rcuh_kind section_kind) { - struct objfile *objfile = per_objfile->objfile; struct dwarf2_section_info *abbrev_section; bfd *abfd; const gdb_byte *info_ptr, *end_ptr; @@ -2403,7 +2405,6 @@ create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, section->get_name (), abbrev_section->get_file_name ()); - section->read (objfile); info_ptr = section->buffer; if (info_ptr == NULL) @@ -2432,8 +2433,8 @@ create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, /* We need to read the type's signature in order to build the hash table, but we don't need anything else just yet. */ - ptr = read_and_check_comp_unit_head (per_objfile, &header, section, - abbrev_section, ptr, section_kind); + ptr = read_and_check_comp_unit_head (&header, section, abbrev_section, + ptr, section_kind); length = header.get_length_with_initial (); @@ -2447,8 +2448,7 @@ create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, continue; } - dwo_unit *dwo_tu - = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, dwo_unit); + dwo_unit *dwo_tu = OBSTACK_ZALLOC (&per_bfd->obstack, dwo_unit); dwo_tu->dwo_file = dwo_file; dwo_tu->signature = header.signature; dwo_tu->type_offset_in_tu = header.type_cu_offset_in_tu; @@ -2478,14 +2478,14 @@ create_dwo_debug_type_hash_table (dwarf2_per_objfile *per_objfile, Note: This function processes DWO files only, not DWP files. */ -static void -create_dwo_debug_types_hash_table - (dwarf2_per_objfile *per_objfile, dwo_file *dwo_file, +void +cutu_reader::create_dwo_debug_types_hash_table + (dwarf2_per_bfd *per_bfd, dwo_file *dwo_file, gdb::array_view<dwarf2_section_info> type_sections) { for (dwarf2_section_info §ion : type_sections) - create_dwo_debug_type_hash_table (per_objfile, dwo_file, §ion, - rcuh_kind::TYPE); + create_dwo_debug_type_hash_table (per_bfd, dwo_file, §ion, + rcuh_kind::TYPE); } /* Add an entry for signature SIG to per_bfd->signatured_types. */ @@ -2610,7 +2610,7 @@ lookup_dwp_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) { dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; - struct dwp_file *dwp_file = get_dwp_file (per_objfile); + dwp_file *dwp_file = per_objfile->per_bfd->dwp_file.get (); gdb_assert (cu->dwo_unit); gdb_assert (dwp_file != NULL); @@ -2652,7 +2652,7 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig) { /* We're in a DWO/DWP file, and we're using .gdb_index. These cases require special processing. */ - if (get_dwp_file (per_objfile) == NULL) + if (per_objfile->per_bfd->dwp_file == nullptr) return lookup_dwo_signatured_type (cu, sig); else return lookup_dwp_signatured_type (cu, sig); @@ -2712,9 +2712,8 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, die_info *stub_comp_unit_die, const char *stub_comp_dir) { - dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_cu *per_cu = cu->per_cu; - struct objfile *objfile = per_objfile->objfile; + struct objfile *objfile = cu->per_objfile->objfile; bfd *abfd; struct dwarf2_section_info *dwo_abbrev_section; @@ -2790,9 +2789,10 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, { signatured_type *sig_type = (struct signatured_type *) per_cu; - m_info_ptr = read_and_check_comp_unit_head (per_objfile, &cu->header, - section, dwo_abbrev_section, + m_info_ptr = read_and_check_comp_unit_head (&cu->header, section, + dwo_abbrev_section, m_info_ptr, rcuh_kind::TYPE); + /* This is not an assert because it can be caused by bad debug info. */ if (sig_type->signature != cu->header.signature) { @@ -2818,7 +2818,7 @@ cutu_reader::read_cutu_die_from_dwo (dwarf2_cu *cu, dwo_unit *dwo_unit, else { m_info_ptr - = read_and_check_comp_unit_head (per_objfile, &cu->header, section, + = read_and_check_comp_unit_head (&cu->header, section, dwo_abbrev_section, m_info_ptr, rcuh_kind::COMPILE); gdb_assert (dwo_unit->sect_off == cu->header.sect_off); @@ -2873,8 +2873,9 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die) Returns nullptr if the specified DWO unit cannot be found. */ -static struct dwo_unit * -lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name) +dwo_unit * +cutu_reader::lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, + const char *dwo_name) { #if CXX_STD_THREAD /* We need a lock here to handle the DWO hash table. */ @@ -3047,7 +3048,7 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, if (this_cu.is_debug_types) { m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, + = read_and_check_comp_unit_head (&cu->header, section, abbrev_section, m_info_ptr, rcuh_kind::TYPE); @@ -3070,7 +3071,7 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, else { m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &cu->header, section, + = read_and_check_comp_unit_head (&cu->header, section, abbrev_section, m_info_ptr, rcuh_kind::COMPILE); @@ -3204,12 +3205,11 @@ cutu_reader::cutu_reader (dwarf2_per_cu &this_cu, m_info_ptr = section->buffer + to_underlying (this_cu.sect_off); const gdb_byte *begin_info_ptr = m_info_ptr; - m_info_ptr - = read_and_check_comp_unit_head (&per_objfile, &m_new_cu->header, section, - abbrev_section, m_info_ptr, - (this_cu.is_debug_types - ? rcuh_kind::TYPE - : rcuh_kind::COMPILE)); + m_info_ptr = read_and_check_comp_unit_head (&m_new_cu->header, section, + abbrev_section, m_info_ptr, + (this_cu.is_debug_types + ? rcuh_kind::TYPE + : rcuh_kind::COMPILE)); m_new_cu->str_offsets_base = parent_cu.str_offsets_base; m_new_cu->addr_base = parent_cu.addr_base; @@ -3510,7 +3510,7 @@ process_skeletonless_type_units (dwarf2_per_objfile *per_objfile, cooked_index_worker_result *storage) { /* Skeletonless TUs in DWP files without .gdb_index is not supported yet. */ - if (get_dwp_file (per_objfile) == nullptr) + if (per_objfile->per_bfd->dwp_file == nullptr) for (const dwo_file_up &file : per_objfile->per_bfd->dwo_files) for (dwo_unit *unit : file->tus) process_skeletonless_type_unit (unit, per_objfile, storage); @@ -3692,6 +3692,7 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, { const gdb_byte *info_ptr; struct objfile *objfile = per_objfile->objfile; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; dwarf_read_debug_printf ("Reading %s for %s", section->get_name (), @@ -3708,20 +3709,19 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, sect_offset sect_off = (sect_offset) (info_ptr - section->buffer); comp_unit_head cu_header; - read_and_check_comp_unit_head (per_objfile, &cu_header, section, - abbrev_section, info_ptr, - section_kind); + read_and_check_comp_unit_head (&cu_header, section, abbrev_section, + info_ptr, section_kind); unsigned int length = cu_header.get_length_with_initial (); /* Save the compilation unit for later lookup. */ if (cu_header.unit_type != DW_UT_type) - this_cu - = per_objfile->per_bfd->allocate_per_cu (section, sect_off, length, is_dwz); + this_cu = per_bfd->allocate_per_cu (section, sect_off, length, is_dwz); else { - auto sig_type = per_objfile->per_bfd->allocate_signatured_type - (section, sect_off, length, is_dwz, cu_header.signature); + auto sig_type + = per_bfd->allocate_signatured_type (section, sect_off, length, + is_dwz, cu_header.signature); signatured_type *sig_ptr = sig_type.get (); sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu; this_cu.reset (sig_type.release ()); @@ -3737,7 +3737,7 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile, } info_ptr = info_ptr + this_cu->length (); - per_objfile->per_bfd->all_units.push_back (std::move (this_cu)); + per_bfd->all_units.push_back (std::move (this_cu)); } } @@ -6307,16 +6307,14 @@ lookup_dwo_file (dwarf2_per_bfd *per_bfd, const char *dwo_name, /* Create the dwo_units for the CUs in a DWO_FILE. Note: This function processes DWO files only, not DWP files. */ -static void -create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) +void +cutu_reader::create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) { dwarf2_per_objfile *per_objfile = cu->per_objfile; - struct objfile *objfile = per_objfile->objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; const gdb_byte *info_ptr, *end_ptr; auto §ion = dwo_file.sections.info; - section.read (objfile); info_ptr = section.buffer; if (info_ptr == NULL) @@ -6536,27 +6534,18 @@ create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) Note: This function processes DWP files only, not DWO files. */ static struct dwp_hash_table * -create_dwp_hash_table (dwarf2_per_objfile *per_objfile, - struct dwp_file *dwp_file, int is_debug_types) +create_dwp_hash_table (dwarf2_per_bfd *per_bfd, struct dwp_file *dwp_file, + dwarf2_section_info &index) { - struct objfile *objfile = per_objfile->objfile; bfd *dbfd = dwp_file->dbfd.get (); - const gdb_byte *index_ptr, *index_end; - struct dwarf2_section_info *index; uint32_t version, nr_columns, nr_units, nr_slots; struct dwp_hash_table *htab; - if (is_debug_types) - index = &dwp_file->sections.tu_index; - else - index = &dwp_file->sections.cu_index; - - if (index->empty ()) + if (index.empty ()) return NULL; - index->read (objfile); - index_ptr = index->buffer; - index_end = index_ptr + index->size; + const gdb_byte *index_ptr = index.buffer; + const gdb_byte *index_end = index_ptr + index.size; /* For Version 5, the version is really 2 bytes of data & 2 bytes of padding. For now it's safe to just read 4 bytes (particularly as it's difficult to @@ -6587,7 +6576,7 @@ create_dwp_hash_table (dwarf2_per_objfile *per_objfile, pulongest (nr_slots), dwp_file->name); } - htab = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack, struct dwp_hash_table); + htab = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwp_hash_table); htab->version = version; htab->nr_columns = nr_columns; htab->nr_units = nr_units; @@ -7526,9 +7515,9 @@ try_open_dwop_file (dwarf2_per_bfd *per_bfd, const char *file_name, int is_dwp, Upon success, the canonicalized path of the file is stored in the bfd, same as symfile_bfd_open. */ -static gdb_bfd_ref_ptr -open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, - const char *comp_dir) +gdb_bfd_ref_ptr +cutu_reader::open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, + const char *comp_dir) { if (IS_ABSOLUTE_PATH (file_name)) return try_open_dwop_file (per_bfd, file_name, @@ -7563,9 +7552,9 @@ open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, /* This function is mapped across the sections and remembers the offset and size of each of the DWO debugging sections we are interested in. */ -static void -dwarf2_locate_dwo_sections (struct objfile *objfile, bfd *abfd, - asection *sectp, dwo_sections *dwo_sections) +void +cutu_reader::locate_dwo_sections (struct objfile *objfile, bfd *abfd, + asection *sectp, dwo_sections *dwo_sections) { const struct dwop_section_names *names = &dwop_section_names; @@ -7612,11 +7601,12 @@ dwarf2_locate_dwo_sections (struct objfile *objfile, bfd *abfd, by PER_CU. This is for the non-DWP case. The result is NULL if DWO_NAME can't be found. */ -static dwo_file_up -open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, - const char *comp_dir) +dwo_file_up +cutu_reader::open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir) { dwarf2_per_objfile *per_objfile = cu->per_objfile; + dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; gdb_bfd_ref_ptr dbfd = open_dwo_file (per_objfile->per_bfd, dwo_name, comp_dir); @@ -7633,16 +7623,16 @@ open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, dwo_file->dbfd = std::move (dbfd); for (asection *sec : gdb_bfd_sections (dwo_file->dbfd)) - dwarf2_locate_dwo_sections (per_objfile->objfile, dwo_file->dbfd.get (), - sec, &dwo_file->sections); + this->locate_dwo_sections (per_objfile->objfile, dwo_file->dbfd.get (), sec, + &dwo_file->sections); create_dwo_cus_hash_table (cu, *dwo_file); if (cu->header.version < 5) - create_dwo_debug_types_hash_table (per_objfile, dwo_file.get (), + create_dwo_debug_types_hash_table (per_bfd, dwo_file.get (), dwo_file->sections.types); else - create_dwo_debug_type_hash_table (per_objfile, dwo_file.get (), + create_dwo_debug_type_hash_table (per_bfd, dwo_file.get (), &dwo_file->sections.info, rcuh_kind::COMPILE); @@ -7810,10 +7800,9 @@ open_dwp_file (dwarf2_per_bfd *per_bfd, const char *file_name) } /* Initialize the use of the DWP file for the current objfile. - By convention the name of the DWP file is ${objfile}.dwp. - The result is NULL if it can't be found. */ + By convention the name of the DWP file is ${objfile}.dwp. */ -static dwp_file_up +static void open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) { struct objfile *objfile = per_objfile->objfile; @@ -7851,7 +7840,7 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) { dwarf_read_debug_printf ("DWP file not found: %s", dwp_name.c_str ()); - return dwp_file_up (); + return; } const char *name = bfd_get_filename (dbfd.get ()); @@ -7865,9 +7854,10 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) dwarf2_locate_common_dwp_sections (objfile, dwp_file->dbfd.get (), sec, dwp_file.get ()); - dwp_file->cus = create_dwp_hash_table (per_objfile, dwp_file.get (), 0); - - dwp_file->tus = create_dwp_hash_table (per_objfile, dwp_file.get (), 1); + dwp_file->cus = create_dwp_hash_table (per_bfd, dwp_file.get (), + dwp_file->sections.cu_index); + dwp_file->tus = create_dwp_hash_table (per_bfd, dwp_file.get (), + dwp_file->sections.tu_index); /* The DWP file version is stored in the hash table. Oh well. */ if (dwp_file->cus && dwp_file->tus @@ -7907,20 +7897,8 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile) bfd_cache_close (dwp_file->dbfd.get ()); - return dwp_file; -} - -/* Wrapper around open_and_init_dwp_file, only open it once. */ - -static struct dwp_file * -get_dwp_file (dwarf2_per_objfile *per_objfile) -{ - if (!per_objfile->per_bfd->dwp_checked) - { - per_objfile->per_bfd->dwp_file = open_and_init_dwp_file (per_objfile); - per_objfile->per_bfd->dwp_checked = 1; - } - return per_objfile->per_bfd->dwp_file.get (); + /* Everything worked, install this dwp_file in the per_bfd. */ + per_objfile->per_bfd->dwp_file = std::move (dwp_file); } /* Subroutine of lookup_dwo_comp_unit, lookup_dwo_type_unit. @@ -7939,22 +7917,23 @@ get_dwp_file (dwarf2_per_objfile *per_objfile) The result is a pointer to the dwo_unit object or NULL if we didn't find it (dwo_id mismatch or couldn't find the DWO/DWP file). */ -static struct dwo_unit * -lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature, int is_debug_types) +dwo_unit * +cutu_reader::lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature, + int is_debug_types) { dwarf2_per_objfile *per_objfile = cu->per_objfile; dwarf2_per_bfd *per_bfd = per_objfile->per_bfd; struct objfile *objfile = per_objfile->objfile; const char *kind = is_debug_types ? "TU" : "CU"; - struct dwp_file *dwp_file; /* First see if there's a DWP file. If we have a DWP file but didn't find the DWO inside it, don't look for the original DWO file. It makes gdb behave differently depending on whether one is debugging in the build tree. */ - dwp_file = get_dwp_file (per_objfile); + dwp_file *dwp_file = per_objfile->per_bfd->dwp_file.get (); + if (dwp_file != NULL) { const struct dwp_hash_table *dwp_htab = @@ -8055,9 +8034,9 @@ lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, /* Lookup the DWO CU DWO_NAME/SIGNATURE referenced from THIS_CU. See lookup_dwo_cutu_unit for details. */ -static struct dwo_unit * -lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, - ULONGEST signature) +dwo_unit * +cutu_reader::lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature) { gdb_assert (!cu->per_cu->is_debug_types); @@ -8067,8 +8046,9 @@ lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir, /* Lookup the DWO TU DWO_NAME/SIGNATURE referenced from THIS_TU. See lookup_dwo_cutu_unit for details. */ -static struct dwo_unit * -lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, const char *comp_dir) +dwo_unit * +cutu_reader::lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir) { gdb_assert (cu->per_cu->is_debug_types); @@ -8111,7 +8091,7 @@ queue_and_load_all_dwo_tus (dwarf2_cu *cu) gdb_assert (cu != nullptr); gdb_assert (!cu->per_cu->is_debug_types); - gdb_assert (get_dwp_file (cu->per_objfile) == nullptr); + gdb_assert (cu->per_objfile->per_bfd->dwp_file == nullptr); dwo_unit = cu->dwo_unit; gdb_assert (dwo_unit != NULL); @@ -19189,7 +19169,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym, /* .debug_loc{,.dwo} may not exist at all, or the offset may be outside the section. If so, fall through to the complaint in the other branch. */ - && attr->as_unsigned () < section->get_size (objfile)) + && attr->as_unsigned () < section->size) { struct dwarf2_loclist_baton *baton; diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h index 3177b19..a9a2aa4 100644 --- a/gdb/dwarf2/read.h +++ b/gdb/dwarf2/read.h @@ -634,9 +634,6 @@ public: /* Set of dwo_file objects. */ dwo_file_up_set dwo_files; - /* True if we've checked for whether there is a DWP file. */ - bool dwp_checked = false; - /* The DWP file if there is one, or NULL. */ dwp_file_up dwp_file; @@ -1028,6 +1025,39 @@ private: const char *read_dwo_str_index (ULONGEST str_index); + gdb_bfd_ref_ptr open_dwo_file (dwarf2_per_bfd *per_bfd, const char *file_name, + const char *comp_dir); + + dwo_file_up open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir); + + void locate_dwo_sections (struct objfile *objfile, bfd *abfd, asection *sectp, + struct dwo_sections *dwo_sections); + + void create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file); + + void create_dwo_debug_types_hash_table + (dwarf2_per_bfd *per_bfd, dwo_file *dwo_file, + gdb::array_view<dwarf2_section_info> type_sections); + + void create_dwo_debug_type_hash_table (dwarf2_per_bfd *per_bfd, + dwo_file *dwo_file, + dwarf2_section_info *section, + rcuh_kind section_kind); + + dwo_unit *lookup_dwo_cutu (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature, + int is_debug_types); + + dwo_unit *lookup_dwo_comp_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir, ULONGEST signature); + + dwo_unit *lookup_dwo_type_unit (dwarf2_cu *cu, const char *dwo_name, + const char *comp_dir); + + dwo_unit *lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, + const char *dwo_name); + /* The bfd of die_section. */ bfd *m_abfd; diff --git a/gdb/dwarf2/section.h b/gdb/dwarf2/section.h index 85da485..b9d3c31 100644 --- a/gdb/dwarf2/section.h +++ b/gdb/dwarf2/section.h @@ -81,19 +81,6 @@ struct dwarf2_section_info If the section is compressed, uncompress it before returning. */ void read (struct objfile *objfile); - /* A helper function that returns the size of a section in a safe way. - If you are positive that the section has been read before using the - size, then it is safe to refer to the dwarf2_section_info object's - "size" field directly. In other cases, you must call this - function, because for compressed sections the size field is not set - correctly until the section has been read. */ - bfd_size_type get_size (struct objfile *objfile) - { - if (!readin) - read (objfile); - return size; - } - /* Issue a complaint that something was outside the bounds of this buffer. */ void overflow_complaint () const; diff --git a/gdb/microblaze-linux-tdep.c b/gdb/microblaze-linux-tdep.c index 0f2f272..8dcbeaa 100644 --- a/gdb/microblaze-linux-tdep.c +++ b/gdb/microblaze-linux-tdep.c @@ -49,6 +49,9 @@ microblaze_linux_memory_remove_breakpoint (struct gdbarch *gdbarch, /* Determine appropriate breakpoint contents and size for this address. */ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen); + /* Make sure we see the memory breakpoints. */ + scoped_restore restore_memory + = make_scoped_restore_show_memory_breakpoints (1); val = target_read_memory (addr, old_contents, bplen); /* If our breakpoint is no longer at the address, this means that the diff --git a/gdb/pager.h b/gdb/pager.h index 3c4fcdf..052337d 100644 --- a/gdb/pager.h +++ b/gdb/pager.h @@ -50,7 +50,6 @@ public: } void emit_style_escape (const ui_file_style &style) override; - void reset_style () override; void flush () override; diff --git a/gdb/printcmd.c b/gdb/printcmd.c index e8be470..2be5eaa 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -2883,7 +2883,7 @@ static void printf_command (const char *arg, int from_tty) { ui_printf (arg, gdb_stdout); - gdb_stdout->reset_style (); + gdb_stdout->emit_style_escape (ui_file_style ()); gdb_stdout->wrap_here (0); gdb_stdout->flush (); } diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index 861e9a3..58998f5 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -948,7 +948,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) else { PyErr_SetString (PyExc_RuntimeError, - _("Line keyword should be an integer or a string. ")); + _("Line keyword should be an integer or a string.")); return -1; } } diff --git a/gdb/python/py-color.c b/gdb/python/py-color.c index 91ad7ae..9e29ee2 100644 --- a/gdb/python/py-color.c +++ b/gdb/python/py-color.c @@ -80,33 +80,33 @@ gdbpy_get_color (PyObject *obj) static PyObject * get_attr (PyObject *obj, PyObject *attr_name) { - if (! PyUnicode_Check (attr_name)) + if (!PyUnicode_Check (attr_name)) return PyObject_GenericGetAttr (obj, attr_name); colorpy_object *self = (colorpy_object *) obj; const ui_file_style::color &color = self->color; - if (! PyUnicode_CompareWithASCIIString (attr_name, "colorspace")) + if (!PyUnicode_CompareWithASCIIString (attr_name, "colorspace")) { int value = static_cast<int> (color.colorspace ()); return gdb_py_object_from_longest (value).release (); } - if (! PyUnicode_CompareWithASCIIString (attr_name, "is_none")) + if (!PyUnicode_CompareWithASCIIString (attr_name, "is_none")) return PyBool_FromLong (color.is_none ()); - if (! PyUnicode_CompareWithASCIIString (attr_name, "is_indexed")) + if (!PyUnicode_CompareWithASCIIString (attr_name, "is_indexed")) return PyBool_FromLong (color.is_indexed ()); - if (! PyUnicode_CompareWithASCIIString (attr_name, "is_direct")) + if (!PyUnicode_CompareWithASCIIString (attr_name, "is_direct")) return PyBool_FromLong (color.is_direct ()); if (color.is_indexed () - && ! PyUnicode_CompareWithASCIIString (attr_name, "index")) + && !PyUnicode_CompareWithASCIIString (attr_name, "index")) return gdb_py_object_from_longest (color.get_value ()).release (); if (color.is_direct () - && ! PyUnicode_CompareWithASCIIString (attr_name, "components")) + && !PyUnicode_CompareWithASCIIString (attr_name, "components")) { uint8_t rgb[3]; color.get_rgb (rgb); @@ -144,7 +144,7 @@ colorpy_escape_sequence (PyObject *self, PyObject *is_fg_obj) return nullptr; } - if (! PyBool_Check (is_fg_obj)) + if (!PyBool_Check (is_fg_obj)) { PyErr_SetString (PyExc_RuntimeError, _("A boolean argument is required.")); @@ -175,17 +175,17 @@ colorpy_init (PyObject *self, PyObject *args, PyObject *kwds) PyObject *colorspace_obj = nullptr; color_space colorspace = color_space::MONOCHROME; - if (! PyArg_ParseTuple (args, "|OO", &value_obj, &colorspace_obj)) + if (!PyArg_ParseTuple (args, "|OO", &value_obj, &colorspace_obj)) return -1; try { - if (colorspace_obj) + if (colorspace_obj != nullptr) { if (PyLong_Check (colorspace_obj)) { long colorspace_id = -1; - if (! gdb_py_int_as_long (colorspace_obj, &colorspace_id)) + if (!gdb_py_int_as_long (colorspace_obj, &colorspace_id)) return -1; if (!color_space_safe_cast (&colorspace, colorspace_id)) error (_("colorspace %ld is out of range."), colorspace_id); @@ -201,11 +201,11 @@ colorpy_init (PyObject *self, PyObject *args, PyObject *kwds) else if (PyLong_Check (value_obj)) { long value = -1; - if (! gdb_py_int_as_long (value_obj, &value)) + if (!gdb_py_int_as_long (value_obj, &value)) return -1; if (value < 0 || value > INT_MAX) error (_("value %ld is out of range."), value); - if (colorspace_obj) + if (colorspace_obj != nullptr) obj->color = ui_file_style::color (colorspace, value); else obj->color = ui_file_style::color (value); @@ -256,7 +256,6 @@ colorpy_init (PyObject *self, PyObject *args, PyObject *kwds) return gdbpy_handle_gdb_exception (-1, except); } - Py_INCREF (self); return 0; } @@ -272,10 +271,10 @@ colorpy_str (PyObject *self) static int gdbpy_initialize_color (void) { - for (auto & pair : colorspace_constants) - if (PyModule_AddIntConstant (gdb_module, pair.name, - static_cast<long> (pair.value)) < 0) - return -1; + for (auto &pair : colorspace_constants) + if (PyModule_AddIntConstant (gdb_module, pair.name, + static_cast<long> (pair.value)) < 0) + return -1; colorpy_object_type.tp_new = PyType_GenericNew; return gdbpy_type_ready (&colorpy_object_type, gdb_module); diff --git a/gdb/testsuite/gdb.python/gdb_leak_detector.py b/gdb/testsuite/gdb.python/gdb_leak_detector.py new file mode 100644 index 0000000..b0f6d47 --- /dev/null +++ b/gdb/testsuite/gdb.python/gdb_leak_detector.py @@ -0,0 +1,120 @@ +# Copyright (C) 2021-2025 Free Software Foundation, Inc. +# +# 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 +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Defines a base class, which can be sub-classed, in order to run +# memory leak tests on some aspects of GDB's Python API. See the +# comments on the gdb_leak_detector class for more details. + +import os +import tracemalloc +import gdb + + +# This class must be sub-classed to create a memory leak test. The +# sub-classes __init__ method should call the parent classes __init__ +# method, and the sub-class should override allocate() and +# deallocate(). See the comments on the various methods below for +# more details of required arguments and expected usage. +class gdb_leak_detector: + + # Class initialisation. FILENAME is the file in which the + # sub-class is defined, usually passed as just '__file__'. This + # is used when looking for memory allocations; only allocations in + # FILENAME are considered. + def __init__(self, filename): + self.filters = [tracemalloc.Filter(True, "*" + os.path.basename(filename))] + + # Internal helper function to actually run the test. Calls the + # allocate() method to allocate an object from GDB's Python API. + # When CLEAR is True the object will then be deallocated by + # calling deallocate(), otherwise, deallocate() is not called. + # + # Finally, this function checks for any memory allocatios + # originating from 'self.filename' that have not been freed, and + # returns the total (in bytes) of the memory that has been + # allocated, but not freed. + def _do_test(self, clear): + # Start tracing, and take a snapshot of the current allocations. + tracemalloc.start() + snapshot1 = tracemalloc.take_snapshot() + + # Generate the GDB Python API object by calling the allocate + # method. + self.allocate() + + # Possibly clear the reference to the allocated object. + if clear: + self.deallocate() + + # Now grab a second snapshot of memory allocations, and stop + # tracing memory allocations. + snapshot2 = tracemalloc.take_snapshot() + tracemalloc.stop() + + # Filter the snapshots; we only care about allocations originating + # from this file. + snapshot1 = snapshot1.filter_traces(self.filters) + snapshot2 = snapshot2.filter_traces(self.filters) + + # Compare the snapshots, this leaves only things that were + # allocated, but not deallocated since the first snapshot. + stats = snapshot2.compare_to(snapshot1, "traceback") + + # Total up all the allocated things. + total = 0 + for stat in stats: + total += stat.size_diff + return total + + # Run the memory leak test. Prints 'PASS' if successful, + # otherwise, raises an exception (of type GdbError). + def run(self): + # The first time we run this some global state will be allocated which + # shows up as memory that is allocated, but not released. So, run the + # test once and discard the result. + self._do_test(True) + + # Now run the test twice, the first time we clear our global reference + # to the allocated object, which should allow Python to deallocate the + # object. The second time we hold onto the global reference, preventing + # Python from performing the deallocation. + bytes_with_clear = self._do_test(True) + bytes_without_clear = self._do_test(False) + + # If there are any allocations left over when we cleared the reference + # (and expected deallocation) then this indicates a leak. + if bytes_with_clear > 0: + raise gdb.GdbError("memory leak when object reference was released") + + # If there are no allocations showing when we hold onto a reference, + # then this likely indicates that the testing infrastructure is broken, + # and we're no longer spotting the allocations at all. + if bytes_without_clear == 0: + raise gdb.GdbError("object is unexpectedly not showing as allocated") + + # Print a PASS message that the TCL script can see. + print("PASS") + + # Sub-classes must override this method. Allocate an object (or + # multiple objects) from GDB's Python API. Store references to + # these objects within SELF. + def allocate(self): + raise NotImplementedError("allocate() not implemented") + + # Sub-classes must override this method. Deallocate the object(s) + # allocated by the allocate() method. All that is required is for + # the references created in allocate() to be set to None. + def deallocate(self): + raise NotImplementedError("allocate() not implemented") diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 1b9c05f..9a901a3 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -707,7 +707,7 @@ proc_with_prefix test_bkpt_explicit_loc {} { delete_breakpoints gdb_test "python bp1 = gdb.Breakpoint (line=bp1)" \ - "RuntimeError.*: Line keyword should be an integer or a string.*" \ + "RuntimeError.*: Line keyword should be an integer or a string\\.\r\n.*" \ "set explicit breakpoint by invalid line type" delete_breakpoints diff --git a/gdb/testsuite/gdb.python/py-color-leak.exp b/gdb/testsuite/gdb.python/py-color-leak.exp new file mode 100644 index 0000000..6d7fa7c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-leak.exp @@ -0,0 +1,28 @@ +# Copyright (C) 2025 Free Software Foundation, Inc. + +# 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 +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This file is part of the GDB testsuite. It checks for memory leaks +# associated with allocating gdb.Color objects. + +load_lib gdb-python.exp + +require allow_python_tests + +standard_testfile + +clean_restart + +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "gdb.Color object deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-color-leak.py b/gdb/testsuite/gdb.python/py-color-leak.py new file mode 100644 index 0000000..50dc315 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-leak.py @@ -0,0 +1,31 @@ +# Copyright (C) 2025 Free Software Foundation, Inc. + +# 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 +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gdb_leak_detector + + +class color_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.color = None + + def allocate(self): + self.color = gdb.Color("red") + + def deallocate(self): + self.color = None + + +color_leak_detector().run() diff --git a/gdb/testsuite/gdb.python/py-color.exp b/gdb/testsuite/gdb.python/py-color.exp index c6f1041..1b8e0c5 100644 --- a/gdb/testsuite/gdb.python/py-color.exp +++ b/gdb/testsuite/gdb.python/py-color.exp @@ -13,8 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# This file is part of the GDB testsuite. -# It tests gdb.parameter and gdb.Parameter. +# This file is part of the GDB testsuite. It tests gdb.Color. load_lib gdb-python.exp diff --git a/gdb/testsuite/gdb.python/py-inferior-leak.exp b/gdb/testsuite/gdb.python/py-inferior-leak.exp index 6710f59..15216ee 100644 --- a/gdb/testsuite/gdb.python/py-inferior-leak.exp +++ b/gdb/testsuite/gdb.python/py-inferior-leak.exp @@ -24,15 +24,5 @@ standard_testfile clean_restart -# Skip this test if the tracemalloc module is not available. -if { ![gdb_py_module_available "tracemalloc"] } { - unsupported "tracemalloc module not available" - return -} - -set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] - -# Source the Python script, this runs the test (which is written -# completely in Python), and either prints PASS, or throws an -# exception. -gdb_test "source ${pyfile}" "PASS" "source python script" +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "gdb.Inferior object deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-inferior-leak.py b/gdb/testsuite/gdb.python/py-inferior-leak.py index 97837dc..38f33c3 100644 --- a/gdb/testsuite/gdb.python/py-inferior-leak.py +++ b/gdb/testsuite/gdb.python/py-inferior-leak.py @@ -14,99 +14,31 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import re -import tracemalloc +import gdb_leak_detector -import gdb -# A global variable in which we store a reference to the gdb.Inferior -# object sent to us in the new_inferior event. -inf = None +class inferior_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.inferior = None + self.__handler = lambda event: setattr(self, "inferior", event.inferior) + gdb.events.new_inferior.connect(self.__handler) + def __del__(self): + gdb.events.new_inferior.disconnect(self.__handler) -# Register the new_inferior event handler. -def new_inferior_handler(event): - global inf - inf = event.inferior + def allocate(self): + output = gdb.execute("add-inferior", False, True) + m = re.search(r"Added inferior (\d+)", output) + if m: + num = int(m.group(1)) + else: + raise RuntimeError("no match") + gdb.execute("remove-inferiors %s" % num) -gdb.events.new_inferior.connect(new_inferior_handler) + def deallocate(self): + self.inferior = None -# A global filters list, we only care about memory allocations -# originating from this script. -filters = [tracemalloc.Filter(True, "*py-inferior-leak.py")] - -# Add a new inferior, and return the number of the new inferior. -def add_inferior(): - output = gdb.execute("add-inferior", False, True) - m = re.search(r"Added inferior (\d+)", output) - if m: - num = int(m.group(1)) - else: - raise RuntimeError("no match") - return num - - -# Run the test. When CLEAR is True we clear the global INF variable -# before comparing the before and after memory allocation traces. -# When CLEAR is False we leave INF set to reference the gdb.Inferior -# object, thus preventing the gdb.Inferior from being deallocated. -def test(clear): - global filters, inf - - # Start tracing, and take a snapshot of the current allocations. - tracemalloc.start() - snapshot1 = tracemalloc.take_snapshot() - - # Create an inferior, this triggers the new_inferior event, which - # in turn holds a reference to the new gdb.Inferior object in the - # global INF variable. - num = add_inferior() - gdb.execute("remove-inferiors %s" % num) - - # Possibly clear the global INF variable. - if clear: - inf = None - - # Now grab a second snapshot of memory allocations, and stop - # tracing memory allocations. - snapshot2 = tracemalloc.take_snapshot() - tracemalloc.stop() - - # Filter the snapshots; we only care about allocations originating - # from this file. - snapshot1 = snapshot1.filter_traces(filters) - snapshot2 = snapshot2.filter_traces(filters) - - # Compare the snapshots, this leaves only things that were - # allocated, but not deallocated since the first snapshot. - stats = snapshot2.compare_to(snapshot1, "traceback") - - # Total up all the deallocated things. - total = 0 - for stat in stats: - total += stat.size_diff - return total - - -# The first time we run this some global state will be allocated which -# shows up as memory that is allocated, but not released. So, run the -# test once and discard the result. -test(True) - -# Now run the test twice, the first time we clear our global reference -# to the gdb.Inferior object, which should allow Python to deallocate -# the object. The second time we hold onto the global reference, -# preventing Python from performing the deallocation. -bytes_with_clear = test(True) -bytes_without_clear = test(False) - -# The bug that used to exist in GDB was that even when we released the -# global reference the gdb.Inferior object would not be deallocated. -if bytes_with_clear > 0: - raise gdb.GdbError("memory leak when gdb.Inferior should be released") -if bytes_without_clear == 0: - raise gdb.GdbError("gdb.Inferior object is no longer allocated") - -# Print a PASS message that the test script can see. -print("PASS") +inferior_leak_detector().run() diff --git a/gdb/testsuite/gdb.python/py-read-memory-leak.exp b/gdb/testsuite/gdb.python/py-read-memory-leak.exp index 0015a57..9ae5eb8 100644 --- a/gdb/testsuite/gdb.python/py-read-memory-leak.exp +++ b/gdb/testsuite/gdb.python/py-read-memory-leak.exp @@ -30,15 +30,5 @@ if ![runto_main] { return -1 } -# Skip this test if the tracemalloc module is not available. -if { ![gdb_py_module_available "tracemalloc"] } { - unsupported "tracemalloc module not available" - return -} - -set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] - -# Source the Python script, this runs the test (which is written -# completely in Python), and either prints PASS, or throws an -# exception. -gdb_test "source ${pyfile}" "PASS" "source python script" +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "buffers returned by read_memory() deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-read-memory-leak.py b/gdb/testsuite/gdb.python/py-read-memory-leak.py index 348403d..71edf47 100644 --- a/gdb/testsuite/gdb.python/py-read-memory-leak.py +++ b/gdb/testsuite/gdb.python/py-read-memory-leak.py @@ -13,81 +13,21 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import os -import tracemalloc +import gdb_leak_detector -import gdb -# A global variable in which we store a reference to the memory buffer -# returned from gdb.Inferior.read_memory(). -mem_buf = None +class read_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.mem_buf = None + self.addr = gdb.parse_and_eval("px") + self.inf = gdb.inferiors()[0] + def allocate(self): + self.mem_buf = self.inf.read_memory(self.addr, 4096) -# A global filters list, we only care about memory allocations -# originating from this script. -filters = [tracemalloc.Filter(True, "*" + os.path.basename(__file__))] + def deallocate(self): + self.mem_buf = None -# Run the test. When CLEAR is True we clear the global INF variable -# before comparing the before and after memory allocation traces. -# When CLEAR is False we leave INF set to reference the gdb.Inferior -# object, thus preventing the gdb.Inferior from being deallocated. -def test(clear): - global filters, mem_buf - - addr = gdb.parse_and_eval("px") - inf = gdb.inferiors()[0] - - # Start tracing, and take a snapshot of the current allocations. - tracemalloc.start() - snapshot1 = tracemalloc.take_snapshot() - - # Read from the inferior, this allocate a memory buffer object. - mem_buf = inf.read_memory(addr, 4096) - - # Possibly clear the global INF variable. - if clear: - mem_buf = None - - # Now grab a second snapshot of memory allocations, and stop - # tracing memory allocations. - snapshot2 = tracemalloc.take_snapshot() - tracemalloc.stop() - - # Filter the snapshots; we only care about allocations originating - # from this file. - snapshot1 = snapshot1.filter_traces(filters) - snapshot2 = snapshot2.filter_traces(filters) - - # Compare the snapshots, this leaves only things that were - # allocated, but not deallocated since the first snapshot. - stats = snapshot2.compare_to(snapshot1, "traceback") - - # Total up all the allocated things. - total = 0 - for stat in stats: - total += stat.size_diff - return total - - -# The first time we run this some global state will be allocated which -# shows up as memory that is allocated, but not released. So, run the -# test once and discard the result. -test(True) - -# Now run the test twice, the first time we clear our global reference -# to the memory buffer object, which should allow Python to deallocate -# the object. The second time we hold onto the global reference, -# preventing Python from performing the deallocation. -bytes_with_clear = test(True) -bytes_without_clear = test(False) - -# The bug that used to exist in GDB was that even when we released the -# global reference the gdb.Inferior object would not be deallocated. -if bytes_with_clear > 0: - raise gdb.GdbError("memory leak when memory buffer should be released") -if bytes_without_clear == 0: - raise gdb.GdbError("memory buffer object is no longer allocated") - -# Print a PASS message that the test script can see. -print("PASS") +read_leak_detector().run() diff --git a/gdb/testsuite/lib/gdb-python.exp b/gdb/testsuite/lib/gdb-python.exp index b4eb40d..e026c1b 100644 --- a/gdb/testsuite/lib/gdb-python.exp +++ b/gdb/testsuite/lib/gdb-python.exp @@ -77,3 +77,24 @@ proc gdb_py_module_available { name } { return ${available} } + +# Run a memory leak test within the Python script FILENAME. This proc +# checks that the required Python modules are available, sets up the +# syspath so that the helper module can be found (in the same +# directory as FILENAME), then loads FILENAME to run the test. +proc gdb_py_run_memory_leak_test { filename testname } { + if { ![gdb_py_module_available "tracemalloc"] } { + unsupported "$testname (tracemalloc module not available)" + } + + gdb_test_no_output -nopass "python import sys" + gdb_test_no_output -nopass \ + "python sys.path.insert(0, \"[file dirname $filename]\")" \ + "setup sys.path" + + set pyfile [gdb_remote_download host ${filename}] + + # Source the Python script, this runs the test, and either prints + # PASS, or throws an exception. + gdb_test "source ${pyfile}" "^PASS" $testname +} diff --git a/gdb/ui-file.c b/gdb/ui-file.c index 09e8b0b..f86b6b1 100644 --- a/gdb/ui-file.c +++ b/gdb/ui-file.c @@ -88,18 +88,6 @@ ui_file::emit_style_escape (const ui_file_style &style) /* See ui-file.h. */ void -ui_file::reset_style () -{ - if (can_emit_style_escape ()) - { - m_applied_style = ui_file_style (); - this->puts (m_applied_style.to_ansi ().c_str ()); - } -} - -/* See ui-file.h. */ - -void ui_file::printchar (int c, int quoter, bool async_safe) { char buf[4]; diff --git a/gdb/ui-file.h b/gdb/ui-file.h index 351cf1f..3919e52 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -123,9 +123,6 @@ public: /* Emit an ANSI style escape for STYLE. */ virtual void emit_style_escape (const ui_file_style &style); - /* Rest the current output style to the empty style. */ - virtual void reset_style (); - /* Print STR, bypassing any paging that might be done by this ui_file. Note that nearly no code should call this -- it's intended for use by gdb_printf, but nothing else. */ @@ -353,12 +350,6 @@ public: m_two->emit_style_escape (style); } - void reset_style () override - { - m_one->reset_style (); - m_two->reset_style (); - } - void puts_unfiltered (const char *str) override { m_one->puts_unfiltered (str); @@ -389,10 +380,6 @@ public: void emit_style_escape (const ui_file_style &style) override { } - - void reset_style () override - { - } }; /* A base class for ui_file types that wrap another ui_file. */ @@ -419,10 +406,6 @@ public: void emit_style_escape (const ui_file_style &style) override { m_stream->emit_style_escape (style); } - /* Rest the current output style to the empty style. */ - void reset_style () override - { m_stream->reset_style (); } - int fd () const override { return m_stream->fd (); } diff --git a/gdb/ui-style.c b/gdb/ui-style.c index b8321c5..b8d73ab 100644 --- a/gdb/ui-style.c +++ b/gdb/ui-style.c @@ -45,7 +45,8 @@ static const char ansi_regex_text[] = /* The compiled form of ansi_regex_text. */ -static regex_t ansi_regex; +static compiled_regex ansi_regex (ansi_regex_text, REG_EXTENDED, + _("Error in ANSI terminal escape sequences regex")); /* This maps 8-color palette to RGB triples. The values come from plain linux terminal. */ @@ -364,7 +365,7 @@ ui_file_style::parse (const char *buf, size_t *n_read) { regmatch_t subexps[NUM_SUBEXPRESSIONS]; - int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0); + int match = ansi_regex.exec (buf, ARRAY_SIZE (subexps), subexps, 0); if (match == REG_NOMATCH) { *n_read = 0; @@ -531,7 +532,7 @@ skip_ansi_escape (const char *buf, int *n_read) { regmatch_t subexps[NUM_SUBEXPRESSIONS]; - int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0); + int match = ansi_regex.exec (buf, ARRAY_SIZE (subexps), subexps, 0); if (match == REG_NOMATCH || buf[subexps[FINAL_SUBEXP].rm_so] != 'm') return false; @@ -539,16 +540,6 @@ skip_ansi_escape (const char *buf, int *n_read) return true; } -void _initialize_ui_style (); -void -_initialize_ui_style () -{ - int code = regcomp (&ansi_regex, ansi_regex_text, REG_EXTENDED); - /* If the regular expression was incorrect, it was a programming - error. */ - gdb_assert (code == 0); -} - /* See ui-style.h. */ const std::vector<color_space> & diff --git a/gdb/utils.c b/gdb/utils.c index 986b906..ce3c26e 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -1407,18 +1407,6 @@ pager_file::emit_style_escape (const ui_file_style &style) } } -/* See pager.h. */ - -void -pager_file::reset_style () -{ - if (can_emit_style_escape ()) - { - m_applied_style = ui_file_style (); - m_wrap_buffer.append (m_applied_style.to_ansi ()); - } -} - /* Wait, so the user can read what's on the screen. Prompt the user to continue by pressing RETURN. 'q' is also provided because telling users what to do in the prompt is more user-friendly than |