@@ -17,6 +17,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/>. */
+#include <cstring>
#include "block.h"
#include "symtab.h"
#include "symfile.h"
@@ -821,6 +822,64 @@ 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)
+{
+ if (num_blocks() <= FIRST_LOCAL_BLOCK)
+ {
+ /* No blocks (except global and static block). */
+ m_blocks.push_back (block);
+ }
+ else
+ {
+ /* blockvector already contains some blocks. Insert new block
+ to a correct place. */
+ auto first = m_blocks.begin () + FIRST_LOCAL_BLOCK;
+ auto last = m_blocks.end ();
+
+ auto insert_before = std::upper_bound (first,
+ last,
+ block,
+ block_ordering_predicate);
+
+ m_blocks.insert (insert_before, block);
+ }
+}
+
+/* See block.h. */
+
+void
+blockvector::sort ()
+{
+ if (num_blocks() > FIRST_LOCAL_BLOCK)
+ {
+ std::sort (blocks ().begin () + FIRST_LOCAL_BLOCK,
+ blocks ().end (),
+ block_ordering_predicate);
+ }
+}
+
+/* See block.h. */
+
+struct blockvector *
+allocate_blockvector(struct obstack *obstack, int nblocks, int capacity)
+{
+ return new (obstack) blockvector(obstack, nblocks, capacity);
+}
+
/* Implement 'maint info blocks' command. If passed an argument then
print a list of all blocks at the given address. With no arguments
then list all blocks at the current address of the current inferior. */
@@ -20,6 +20,7 @@
#ifndef BLOCK_H
#define BLOCK_H
+#include <algorithm>
#include "dictionary.h"
#include "gdbsupport/array-view.h"
#include "gdbsupport/next-iterator.h"
@@ -416,41 +417,60 @@ struct global_block : public block
struct blockvector
{
+ void* operator new (size_t size, struct obstack *obstack)
+ {
+ return obstack_alloc (obstack, size);
+ }
+
+ void* operator new[] (size_t size, struct obstack *obstack)
+ {
+ return obstack_alloc (obstack, size);
+ }
+
+ void operator delete (void *memory) {}
+ void operator delete[] (void *memory) {}
+
+ blockvector (struct obstack *obstack, int nblocks, int capacity = 0)
+ : m_map (nullptr),
+ m_blocks (0, nullptr, obstack_allocator<struct block *> (obstack))
+ {
+ m_blocks.reserve (std::max (nblocks, capacity));
+ m_blocks.resize (nblocks, nullptr);
+ }
+
/* 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. */
struct block *block (size_t i)
- { return this->blocks ()[i]; }
+ { return m_blocks[i]; }
/* Const version of the above. */
const struct block *block (size_t i) const
- { return this->blocks ()[i]; }
+ { return m_blocks[i]; }
/* Set the block at index I. */
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 global_block *global_block ()
@@ -483,19 +503,23 @@ struct blockvector
void set_map (addrmap_fixed *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. */
addrmap_fixed *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 for NBLOCKS blocks with enough storage to
+ hold up to CAPACITY blocks. CAPACITY defaults to NBLOCKS. */
+struct blockvector *allocate_blockvector(struct obstack *obstack,
+ int nblocks, int capacity = 0);
+
extern const struct blockvector *blockvector_for_pc (CORE_ADDR,
const struct block **);
@@ -429,10 +429,7 @@ 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
@@ -440,7 +437,6 @@ buildsym_compunit::make_blockvector ()
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);
@@ -517,7 +517,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;
@@ -552,18 +551,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
@@ -242,8 +242,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 *);
@@ -4499,17 +4497,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);
+ = const_cast<struct blockvector*> (s->compunit ()->blockvector ());
+ bv->add_block (b);
}
/* Add a new linenumber entry (LINENO,ADR) to a linevector LT.
@@ -4632,7 +4621,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 ());
@@ -4700,21 +4689,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
@@ -20,6 +20,8 @@
#if !defined (GDB_OBSTACK_H)
#define GDB_OBSTACK_H 1
+#include <limits>
+#include <type_traits>
#include "obstack.h"
/* Utility macros - wrap obstack alloc into something more robust. */
@@ -157,4 +159,54 @@ 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> &t, const obstack_allocator<U> &u)
+{
+ return (std::is_same<T, U>::value_type) && (t.m_obstack == u.m_obstack);
+}
+template <class T, class U>
+bool operator!=(const obstack_allocator<T> &t, const obstack_allocator<U> &u)
+{
+ return ! (t == u);
+}
+
#endif