summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Vrany <jan.vrany@labware.com>2022-03-23 17:08:13 +0000
committerJan Vrany <jan.vrany@labware.com>2023-04-21 16:30:11 +0100
commitb80fb831f563ffd35e2885e02bb9e75873e9bba2 (patch)
tree5f4c02f7474bf62af3041182299a655dbd15eb6b
parentf1398516ec039fa90a6914d85715086c1bfd7483 (diff)
downloadbinutils-gdb-b80fb831f563ffd35e2885e02bb9e75873e9bba2.tar.gz
gdb: use std::vector<> to hold on blocks in struct blockvector
This commit changes internal implementation of struct blockvector to use std::vector<> rather than flexible array. The main motivation for this change is to simplify adding blocks to existing symtab. This feature will be used later by Python API to build objfiles and symtabs dynamically (similarly to JIT reader API). To do so, this commit 1. introduces obstack_allocator, an implementation of Allocator concept that allocates memory on obstack. 2. uses std::vector<> with the above allocator to hold on blocks 3. updates users. As a side-effect of this change, blockvectors allocated in mdebugread.c are obstack-allocated rather than xzalloc()ated which seems to be the correct thing to do. Also, code got simpler. The downside might be higher memory consumption. The memory overhead of std::vector should be small enough not to be of a concern. More concerning is fact then one may leak obstack memory when excessively adding blocks. However, blockvectors are not added blocks after initial allocation at the moment (except in mdebugread.c) so this is not a problem for existing code.
-rw-r--r--gdb/block.c72
-rw-r--r--gdb/block.h35
-rw-r--r--gdb/buildsym.c8
-rw-r--r--gdb/jit.c8
-rw-r--r--gdb/mdebugread.c33
-rw-r--r--gdbsupport/gdb_obstack.h45
6 files changed, 143 insertions, 58 deletions
diff --git a/gdb/block.c b/gdb/block.c
index 4e40247b79c..ad73c1cb37b 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -842,3 +842,75 @@ make_blockranges (struct objfile *objfile,
return blr;
}
+static bool
+block_ordering_predicate(struct block *b1, struct block *b2)
+{
+ CORE_ADDR start1 = b1->start ();
+ CORE_ADDR start2 = b2->start ();
+
+ if (start1 != start2)
+ return start1 < start2;
+ return (b2->end () < b1->end ());
+}
+
+/* See block.h. */
+
+void
+blockvector::add_block (struct block *block)
+{
+ gdb_assert (num_blocks() >= FIRST_LOCAL_BLOCK);
+
+ auto global_block = this->block (GLOBAL_BLOCK);
+ auto static_block = this->block (STATIC_BLOCK);
+
+ if (num_blocks() <= FIRST_LOCAL_BLOCK)
+ {
+ /* No blocks (except global and static block). */
+ m_blocks.push_back (block);
+ global_block->set_start (block->start ());
+ static_block->set_start (block->start ());
+ global_block->set_end (block->end ());
+ static_block->set_end (block->end ());
+ }
+ else
+ {
+ /* Symtab already contains some blocks. Insert new block
+ to a correct place and update global and static block
+ start and end address. */
+ auto insert_before = std::upper_bound(m_blocks.begin(), m_blocks.end(),
+ block,
+ block_ordering_predicate);
+ m_blocks.insert(insert_before, block);
+ if (global_block->start () > block->start ())
+ {
+ global_block->set_start (block->start ());
+ static_block->set_start (block->start ());
+ }
+ if (global_block->end () < block->end ())
+ {
+ global_block->set_end (block->end ());
+ static_block->set_end (block->end ());
+ }
+ }
+}
+
+/* See block.h. */
+
+void
+blockvector::sort ()
+{
+ if (num_blocks() > FIRST_LOCAL_BLOCK)
+ {
+ std::sort (&m_blocks.data()[FIRST_LOCAL_BLOCK],
+ &m_blocks.data()[num_blocks()],
+ block_ordering_predicate);
+ }
+}
+
+/* See block.h. */
+
+struct blockvector *
+allocate_blockvector(struct obstack *obstack, int nblocks)
+{
+ return new (obstack) blockvector(obstack, nblocks);
+}
diff --git a/gdb/block.h b/gdb/block.h
index cdcee0844ec..26a21aa411e 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -330,19 +330,24 @@ struct global_block : public block
struct compunit_symtab *compunit_symtab = nullptr;
};
-struct blockvector
+struct blockvector : public allocate_on_obstack
{
+ blockvector (struct obstack *obstack, int nblocks)
+ : m_map (nullptr),
+ m_blocks (nblocks, nullptr, obstack_allocator<struct block *> (obstack))
+ {}
+
/* Return a view on the blocks of this blockvector. */
gdb::array_view<struct block *> blocks ()
{
- return gdb::array_view<struct block *> (m_blocks, m_num_blocks);
+ return gdb::array_view<struct block *> (m_blocks.data (), m_blocks.size ());
}
/* Const version of the above. */
gdb::array_view<const struct block *const> blocks () const
{
- const struct block **blocks = (const struct block **) m_blocks;
- return gdb::array_view<const struct block *const> (blocks, m_num_blocks);
+ const struct block **blocks = (const struct block **) m_blocks.data ();
+ return gdb::array_view<const struct block *const> (blocks, m_blocks.size ());
}
/* Return the block at index I. */
@@ -357,16 +362,14 @@ struct blockvector
void set_block (int i, struct block *block)
{ m_blocks[i] = block; }
- /* Set the number of blocks of this blockvector.
-
- The storage of blocks is done using a flexible array member, so the number
- of blocks set here must agree with what was effectively allocated. */
- void set_num_blocks (int num_blocks)
- { m_num_blocks = num_blocks; }
+ /* Add BLOCK, making sure blocks are ordered by code-addresses
+ as required. Update global and static block start and end
+ adresses accordingly. */
+ void add_block(struct block *block);
/* Return the number of blocks in this blockvector. */
int num_blocks () const
- { return m_num_blocks; }
+ { return m_blocks.size (); }
/* Return the global block of this blockvector. */
struct block *global_block ()
@@ -396,19 +399,21 @@ struct blockvector
void set_map (addrmap *map)
{ m_map = map; }
+ void sort ();
+
private:
/* An address map mapping addresses to blocks in this blockvector.
This pointer is zero if the blocks' start and end addresses are
enough. */
struct addrmap *m_map;
- /* Number of blocks in the list. */
- int m_num_blocks;
-
/* The blocks themselves. */
- struct block *m_blocks[1];
+ std::vector<struct block *, obstack_allocator<struct block *>> m_blocks;
};
+/* Allocate new blockvector with space for NBLOCKS blocks. */
+struct blockvector *allocate_blockvector(struct obstack *obstack, int nblocks);
+
extern const struct blockvector *blockvector_for_pc (CORE_ADDR,
const struct block **);
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index f000233dafa..54aaa0309dc 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -435,18 +435,14 @@ buildsym_compunit::make_blockvector ()
{
}
- blockvector = (struct blockvector *)
- obstack_alloc (&m_objfile->objfile_obstack,
- (sizeof (struct blockvector)
- + (i - 1) * sizeof (struct block *)));
+ blockvector = allocate_blockvector(&m_objfile->objfile_obstack, i);
/* Copy the blocks into the blockvector. This is done in reverse
order, which happens to put the blocks into the proper order
(ascending starting address). finish_block has hair to insert
each block into the list after its subblocks in order to make
sure this is true. */
-
- blockvector->set_num_blocks (i);
+
for (next = m_pending_blocks; next; next = next->next)
blockvector->set_block (--i, next->block);
diff --git a/gdb/jit.c b/gdb/jit.c
index e085d562333..bbd48125a64 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -515,7 +515,6 @@ static void
finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile)
{
struct compunit_symtab *cust;
- size_t blockvector_size;
CORE_ADDR begin, end;
struct blockvector *bv;
@@ -550,18 +549,13 @@ finalize_symtab (struct gdb_symtab *stab, struct objfile *objfile)
filetab->set_linetable (new_table);
}
- blockvector_size = (sizeof (struct blockvector)
- + (actual_nblocks - 1) * sizeof (struct block *));
- bv = (struct blockvector *) obstack_alloc (&objfile->objfile_obstack,
- blockvector_size);
+ bv = allocate_blockvector(&objfile->objfile_obstack, actual_nblocks);
cust->set_blockvector (bv);
/* At the end of this function, (begin, end) will contain the PC range this
entire blockvector spans. */
- bv->set_map (nullptr);
begin = stab->blocks.front ().begin;
end = stab->blocks.front ().end;
- bv->set_num_blocks (actual_nblocks);
/* First run over all the gdb_block objects, creating a real block
object for each. Simultaneously, keep setting the real_block
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index 697ce0b5b1a..22bbbb0e03e 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -243,8 +243,6 @@ static struct compunit_symtab *new_symtab (const char *, int, struct objfile *);
static struct linetable *new_linetable (int);
-static struct blockvector *new_bvect (int);
-
static struct type *parse_type (int, union aux_ext *, unsigned int, int *,
int, const char *);
@@ -4503,18 +4501,8 @@ add_block (struct block *b, struct symtab *s)
{
/* Cast away "const", but that's ok because we're building the
symtab and blockvector here. */
- struct blockvector *bv
- = (struct blockvector *) s->compunit ()->blockvector ();
-
- bv = (struct blockvector *) xrealloc ((void *) bv,
- (sizeof (struct blockvector)
- + bv->num_blocks ()
- * sizeof (struct block)));
- if (bv != s->compunit ()->blockvector ())
- s->compunit ()->set_blockvector (bv);
-
- bv->set_block (bv->num_blocks (), b);
- bv->set_num_blocks (bv->num_blocks () + 1);
+ auto bv = const_cast<struct blockvector*> (s->compunit ()->blockvector ());
+ bv->add_block (b);
}
/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
@@ -4637,7 +4625,7 @@ new_symtab (const char *name, int maxlines, struct objfile *objfile)
lang = cust->language ();
/* All symtabs must have at least two blocks. */
- bv = new_bvect (2);
+ bv = allocate_blockvector(&objfile->objfile_obstack, 2);
bv->set_block (GLOBAL_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK, lang));
bv->set_block (STATIC_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK, lang));
bv->static_block ()->set_superblock (bv->global_block ());
@@ -4705,21 +4693,6 @@ shrink_linetable (struct linetable *lt)
* sizeof (lt->item))));
}
-/* Allocate and zero a new blockvector of NBLOCKS blocks. */
-
-static struct blockvector *
-new_bvect (int nblocks)
-{
- struct blockvector *bv;
- int size;
-
- size = sizeof (struct blockvector) + nblocks * sizeof (struct block *);
- bv = (struct blockvector *) xzalloc (size);
- bv->set_num_blocks (nblocks);
-
- return bv;
-}
-
/* Allocate and zero a new block of language LANGUAGE, and set its
BLOCK_MULTIDICT. If function is non-zero, assume the block is
associated to a function, and make sure that the symbols are stored
diff --git a/gdbsupport/gdb_obstack.h b/gdbsupport/gdb_obstack.h
index dbd8fab54d4..2dff1e5ce33 100644
--- a/gdbsupport/gdb_obstack.h
+++ b/gdbsupport/gdb_obstack.h
@@ -20,6 +20,7 @@
#if !defined (GDB_OBSTACK_H)
#define GDB_OBSTACK_H 1
+#include <limits>
#include "obstack.h"
/* Utility macros - wrap obstack alloc into something more robust. */
@@ -153,4 +154,48 @@ struct allocate_on_obstack
void operator delete[] (void *memory) {}
};
+/* Implementation of Allocator concept using obstack to
+ allocate memory. This allows standard containers to be
+ used with obstack. */
+
+template <typename T>
+class obstack_allocator
+{
+public:
+ typedef T value_type;
+
+ obstack_allocator (struct obstack *obstack)
+ : m_obstack(obstack)
+ {}
+
+ template <typename U> constexpr obstack_allocator (const obstack_allocator<U>& allocator) noexcept
+ : m_obstack(allocator.m_obstack)
+ {}
+
+ T* allocate (std::size_t n)
+ {
+ if (n > std::numeric_limits<std::size_t>::max () / sizeof (T))
+ throw std::bad_array_new_length ();
+
+ if (auto p = static_cast<T*> (obstack_alloc (m_obstack, n * sizeof (T))))
+ {
+ return p;
+ }
+
+ throw std::bad_alloc ();
+ }
+
+ void deallocate(T* p, std::size_t n) noexcept
+ {}
+
+private:
+
+ struct obstack *m_obstack;
+};
+
+template <class T, class U>
+bool operator==(const obstack_allocator <T>&, const obstack_allocator <U>&) { return true; }
+template <class T, class U>
+bool operator!=(const obstack_allocator <T>&, const obstack_allocator <U>&) { return false; }
+
#endif