Handle frame pointer omission (#21), part 1: ContainedRangeMap. r=bryner.

- ContainedRangeMap is the data structure that will be used to store and
   look up debugging information for frames by instruction address.  The
   debugging information includes a way to locate the calling frame in
   the absence of a saved frame pointer.
 - Restructure RangeMap into an -inl file to match ContainedRangeMap.

http://groups.google.com/group/airbag-dev/browse_thread/thread/c5823bfc1828ed42


git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@29 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
mmentovai 2006-09-20 16:20:15 +00:00
parent 82a6c6037b
commit 8c2a4def4e
13 changed files with 7956 additions and 6065 deletions

View file

@ -39,6 +39,8 @@ src_libairbag_la_SOURCES = \
src/google/minidump_processor.h \
src/google/stack_frame.h \
src/google/symbol_supplier.h \
src/processor/contained_range_map.h \
src/processor/contained_range_map-inl.h \
src/processor/linked_ptr.h \
src/processor/memory_region.h \
src/processor/minidump.cc \
@ -46,6 +48,7 @@ src_libairbag_la_SOURCES = \
src/processor/minidump_format.h \
src/processor/minidump_processor.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/source_line_resolver.cc \
src/processor/source_line_resolver.h \
src/processor/stackwalker.cc \
@ -62,6 +65,7 @@ bin_PROGRAMS = \
## Tests
check_PROGRAMS = \
src/processor/contained_range_map_unittest \
src/processor/minidump_processor_unittest \
src/processor/range_map_unittest \
src/processor/source_line_resolver_unittest
@ -71,6 +75,9 @@ check_SCRIPTS = \
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
TESTS_ENVIRONMENT =
src_processor_contained_range_map_unittest_SOURCES = \
src/processor/contained_range_map_unittest.cc
src_processor_minidump_processor_unittest_SOURCES = \
src/processor/minidump_processor_unittest.cc
src_processor_minidump_processor_unittest_LDADD = \

View file

@ -1,4 +1,4 @@
# Makefile.in generated by automake 1.9.5 from Makefile.am.
# Makefile.in generated by automake 1.9.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@ -31,8 +31,6 @@
SOURCES = $(src_libairbag_la_SOURCES) $(src_processor_minidump_dump_SOURCES) $(src_processor_minidump_processor_unittest_SOURCES) $(src_processor_minidump_stackwalk_SOURCES) $(src_processor_range_map_unittest_SOURCES) $(src_processor_source_line_resolver_unittest_SOURCES)
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
@ -57,7 +55,8 @@ build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = src/processor/minidump_dump$(EXEEXT) \
src/processor/minidump_stackwalk$(EXEEXT)
check_PROGRAMS = src/processor/minidump_processor_unittest$(EXEEXT) \
check_PROGRAMS = src/processor/contained_range_map_unittest$(EXEEXT) \
src/processor/minidump_processor_unittest$(EXEEXT) \
src/processor/range_map_unittest$(EXEEXT) \
src/processor/source_line_resolver_unittest$(EXEEXT)
noinst_PROGRAMS =
@ -96,6 +95,11 @@ am_src_libairbag_la_OBJECTS = src/processor/minidump.lo \
src_libairbag_la_OBJECTS = $(am_src_libairbag_la_OBJECTS)
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am_src_processor_contained_range_map_unittest_OBJECTS = \
src/processor/contained_range_map_unittest.$(OBJEXT)
src_processor_contained_range_map_unittest_OBJECTS = \
$(am_src_processor_contained_range_map_unittest_OBJECTS)
src_processor_contained_range_map_unittest_LDADD = $(LDADD)
am_src_processor_minidump_dump_OBJECTS = \
src/processor/minidump_dump.$(OBJEXT)
src_processor_minidump_dump_OBJECTS = \
@ -149,12 +153,14 @@ CCLD = $(CC)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(src_libairbag_la_SOURCES) \
$(src_processor_contained_range_map_unittest_SOURCES) \
$(src_processor_minidump_dump_SOURCES) \
$(src_processor_minidump_processor_unittest_SOURCES) \
$(src_processor_minidump_stackwalk_SOURCES) \
$(src_processor_range_map_unittest_SOURCES) \
$(src_processor_source_line_resolver_unittest_SOURCES)
DIST_SOURCES = $(src_libairbag_la_SOURCES) \
$(src_processor_contained_range_map_unittest_SOURCES) \
$(src_processor_minidump_dump_SOURCES) \
$(src_processor_minidump_processor_unittest_SOURCES) \
$(src_processor_minidump_stackwalk_SOURCES) \
@ -204,6 +210,7 @@ EGREP = @EGREP@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
@ -229,12 +236,9 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_F77 = @ac_ct_F77@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
@ -251,23 +255,30 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
@ -275,7 +286,6 @@ target_alias = @target_alias@
# This allows #includes to be relative to src/
AM_CPPFLAGS = -I$(top_srcdir)/src
docdir = $(prefix)/share/doc/$(PACKAGE)-$(VERSION)
dist_doc_DATA = \
AUTHORS \
COPYING \
@ -290,6 +300,8 @@ src_libairbag_la_SOURCES = \
src/google/minidump_processor.h \
src/google/stack_frame.h \
src/google/symbol_supplier.h \
src/processor/contained_range_map.h \
src/processor/contained_range_map-inl.h \
src/processor/linked_ptr.h \
src/processor/memory_region.h \
src/processor/minidump.cc \
@ -297,6 +309,7 @@ src_libairbag_la_SOURCES = \
src/processor/minidump_format.h \
src/processor/minidump_processor.cc \
src/processor/range_map.h \
src/processor/range_map-inl.h \
src/processor/source_line_resolver.cc \
src/processor/source_line_resolver.h \
src/processor/stackwalker.cc \
@ -310,6 +323,9 @@ check_SCRIPTS = \
TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
TESTS_ENVIRONMENT =
src_processor_contained_range_map_unittest_SOURCES = \
src/processor/contained_range_map_unittest.cc
src_processor_minidump_processor_unittest_SOURCES = \
src/processor/minidump_processor_unittest.cc
@ -500,6 +516,12 @@ clean-noinstPROGRAMS:
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
done
src/processor/contained_range_map_unittest.$(OBJEXT): \
src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/contained_range_map_unittest$(EXEEXT): $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_DEPENDENCIES) src/processor/$(am__dirstamp)
@rm -f src/processor/contained_range_map_unittest$(EXEEXT)
$(CXXLINK) $(src_processor_contained_range_map_unittest_LDFLAGS) $(src_processor_contained_range_map_unittest_OBJECTS) $(src_processor_contained_range_map_unittest_LDADD) $(LIBS)
src/processor/minidump_dump.$(OBJEXT): src/processor/$(am__dirstamp) \
src/processor/$(DEPDIR)/$(am__dirstamp)
src/processor/minidump_dump$(EXEEXT): $(src_processor_minidump_dump_OBJECTS) $(src_processor_minidump_dump_DEPENDENCIES) src/processor/$(am__dirstamp)
@ -532,6 +554,7 @@ src/processor/source_line_resolver_unittest$(EXEEXT): $(src_processor_source_lin
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f src/processor/contained_range_map_unittest.$(OBJEXT)
-rm -f src/processor/minidump.$(OBJEXT)
-rm -f src/processor/minidump.lo
-rm -f src/processor/minidump_dump.$(OBJEXT)
@ -551,6 +574,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/contained_range_map_unittest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_dump.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@src/processor/$(DEPDIR)/minidump_processor.Plo@am__quote@

1621
aclocal.m4 vendored

File diff suppressed because it is too large Load diff

11647
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -27,9 +27,6 @@ AC_PROG_CC
AC_PROG_CPP
AC_PROG_CXX
dnl Prevent AC_PROG_LIBTOOL from looking for Fortran support. We don't use
dnl any Fortran here.
define(AC_PROG_F77)
AC_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)

View file

@ -0,0 +1,157 @@
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// contained_range_map-inl.h: Hierarchically-organized range map implementation.
//
// See contained_range_map.h for documentation.
//
// Author: Mark Mentovai
#ifndef PROCESSOR_CONTAINED_RANGE_MAP_INL_H__
#define PROCESSOR_CONTAINED_RANGE_MAP_INL_H__
#include "processor/contained_range_map.h"
namespace google_airbag {
template<typename AddressType, typename EntryType>
ContainedRangeMap<AddressType, EntryType>::~ContainedRangeMap() {
// Clear frees the children pointed to by the map, and frees the map itself.
Clear();
}
template<typename AddressType, typename EntryType>
bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
const AddressType &base, const AddressType &size, const EntryType &entry) {
AddressType high = base + size - 1;
// Check for undersize or overflow.
if (size <= 0 || high < base)
return false;
if (!map_)
map_ = new AddressToRangeMap();
MapIterator iterator_base = map_->lower_bound(base);
MapIterator iterator_high = map_->lower_bound(high);
MapConstIterator iterator_end = map_->end();
if (iterator_base == iterator_high && iterator_base != iterator_end &&
base >= iterator_base->second->base_) {
// The new range is entirely within an existing child range.
// If the new range's geometry is exactly equal to an existing child
// range's, it violates the containment rules, and an attempt to store
// it must fail. iterator_base->first contains the key, which was the
// containing child's high address.
if (iterator_base->second->base_ == base && iterator_base->first == high)
return false;
// Pass the new range on to the child to attempt to store.
return iterator_base->second->StoreRange(base, size, entry);
}
// iterator_high might refer to an irrelevant range: one whose base address
// is higher than the new range's high address. Set contains_high to true
// only if iterator_high refers to a range that is at least partially
// within the new range.
bool contains_high = iterator_high != iterator_end &&
high >= iterator_high->second->base_;
// If the new range encompasses any existing child ranges, it must do so
// fully. Partial containment isn't allowed.
if ((iterator_base != iterator_end && base > iterator_base->second->base_) ||
(contains_high && high < iterator_high->first)) {
return false;
}
// When copying and erasing contained ranges, the "end" iterator needs to
// point one past the last item of the range to copy. If contains_high is
// false, the iterator's already in the right place; the increment is safe
// because contains_high can't be true if iterator_high == iterator_end.
if (contains_high)
++iterator_high;
// Optimization: if the iterators are equal, no child ranges would be
// moved. Create the new child range with a NULL map to conserve space
// in leaf nodes, of which there will be many.
AddressToRangeMap *child_map = NULL;
if (iterator_base != iterator_high) {
// The children of this range that are contained by the new range must
// be transferred over to the new range. Create the new child range map
// and copy the pointers to range maps it should contain into it.
child_map = new AddressToRangeMap(iterator_base, iterator_high);
// Remove the copied child pointers from this range's map of children.
map_->erase(iterator_base, iterator_high);
}
// Store the new range in the map by its high address. Any children that
// the new child range contains were formerly children of this range but
// are now this range's grandchildren. Ownership of these is transferred
// to the new child range.
map_->insert(MapValue(high,
new ContainedRangeMap(base, entry, child_map)));
return true;
}
template<typename AddressType, typename EntryType>
bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange(
const AddressType &address, EntryType *entry) const {
if (!entry || !map_)
return false;
// Get an iterator to the child range whose high address is equal to or
// greater than the supplied address. If the supplied address is higher
// than all of the high addresses in the range, then this range does not
// contain a child at address, so return false. If the supplied address
// is lower than the base address of the child range, then it is not within
// the child range, so return false.
MapConstIterator iterator = map_->lower_bound(address);
if (iterator == map_->end() || address < iterator->second->base_)
return false;
// The child in iterator->second contains the specified address. Find out
// if it has a more-specific descendant that also contains it. If it does,
// it will set |entry| appropriately. If not, set |entry| to the child.
if (!iterator->second->RetrieveRange(address, entry))
*entry = iterator->second->entry_;
return true;
}
template<typename AddressType, typename EntryType>
void ContainedRangeMap<AddressType, EntryType>::Clear() {
if (map_) {
MapConstIterator end = map_->end();
for (MapConstIterator child = map_->begin(); child != end; ++child)
delete child->second;
delete map_;
map_ = NULL;
}
}
} // namespace google_airbag
#endif // PROCESSOR_CONTAINED_RANGE_MAP_INL_H__

View file

@ -0,0 +1,131 @@
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// contained_range_map.h: Hierarchically-organized range maps.
//
// A contained range map is similar to a standard range map, except it allows
// objects to be organized hierarchically. A contained range map allows
// objects to contain other objects. It is not sensitive to the order that
// objects are added to the map: larger, more general, containing objects
// may be added either before or after smaller, more specific, contained
// ones.
//
// Contained range maps guarantee that each object may only contain smaller
// objects than itself, and that a parent object may only contain child
// objects located entirely within the parent's address space. Attempts
// to introduce objects (via StoreRange) that violate these rules will fail.
// Retrieval (via RetrieveRange) always returns the most specific (smallest)
// object that contains the address being queried. Note that while it is
// not possible to insert two objects into a map that have exactly the same
// geometry (base address and size), it is possible to completely mask a
// larger object by inserting smaller objects that entirely fill the larger
// object's address space.
//
// Internally, contained range maps are implemented as a tree. Each tree
// node except for the root node describes an object in the map. Each node
// maintains its list of children in a map similar to a standard range map,
// keyed by the highest address that each child occupies. Each node's
// children occupy address ranges entirely within the node. The root node
// is the only node directly accessible to the user, and represents the
// entire address space.
//
// Author: Mark Mentovai
#ifndef PROCESSOR_CONTAINED_RANGE_MAP_H__
#define PROCESSOR_CONTAINED_RANGE_MAP_H__
#include <map>
namespace google_airbag {
template<typename AddressType, typename EntryType>
class ContainedRangeMap {
public:
// The default constructor creates a ContainedRangeMap with no geometry
// and no entry, and as such is only suitable for the root node of a
// ContainedRangeMap tree.
ContainedRangeMap() : base_(), entry_(), map_(NULL) {}
~ContainedRangeMap();
// Inserts a range into the map. If the new range is encompassed by
// an existing child range, the new range is passed into the child range's
// StoreRange method. If the new range encompasses any existing child
// ranges, those child ranges are moved to the new range, becoming
// grandchildren of this ContainedRangeMap. Returns false for a
// parameter error, or if the ContainedRangeMap hierarchy guarantees
// would be violated.
bool StoreRange(const AddressType &base,
const AddressType &size,
const EntryType &entry);
// Retrieves the most specific (smallest) descendant range encompassing
// the specified address. This method will only return entries held by
// child ranges, and not the entry contained by |this|. This is necessary
// to support a sparsely-populated root range. If no descendant range
// encompasses the address, or if there is a parameter error, returns
// false.
bool RetrieveRange(const AddressType &address, EntryType *entry) const;
// Removes all children. Note that Clear only removes descendants,
// leaving the node on which it is called intact. Because the only
// meaningful things contained by a root node are descendants, this
// is sufficient to restore an entire ContainedRangeMap to its initial
// empty state when called on the root node.
void Clear();
private:
// AddressToRangeMap stores pointers. This makes reparenting simpler in
// StoreRange, because it doesn't need to copy entire objects.
typedef std::map<AddressType, ContainedRangeMap *> AddressToRangeMap;
typedef typename AddressToRangeMap::const_iterator MapConstIterator;
typedef typename AddressToRangeMap::iterator MapIterator;
typedef typename AddressToRangeMap::value_type MapValue;
// Creates a new ContainedRangeMap with the specified base address, entry,
// and initial child map, which may be NULL. This is only used internally
// by ContainedRangeMap when it creates a new child.
ContainedRangeMap(const AddressType &base, const EntryType &entry,
AddressToRangeMap *map)
: base_(base), entry_(entry), map_(map) {}
// The base address of this range. The high address does not need to
// be stored, because it is used as the key to an object in its parent's
// map, and all ContainedRangeMaps except for the root range are contained
// within maps. The root range does not actually contain an entry, so its
// base_ field is meaningless, and the fact that it has no parent and thus
// no key is unimportant. For this reason, the base_ field should only be
// is accessed on child ContainedRangeMap objects, and never on |this|.
const AddressType base_;
// The entry corresponding to this range. The root range does not
// actually contain an entry, so its entry_ field is meaningless. For
// this reason, the entry_ field should only be accessed on child
// ContainedRangeMap objects, and never on |this|.
const EntryType entry_;
// The map containing child ranges, keyed by each child range's high
// address. This is a pointer to avoid allocating map structures for
// leaf nodes, where they are not needed.
AddressToRangeMap *map_;
};
} // namespace google_airbag
#endif // PROCESSOR_CONTAINED_RANGE_MAP_H__

View file

@ -0,0 +1,238 @@
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// contained_range_map_unittest.cc: Unit tests for ContainedRangeMap
//
// Author: Mark Mentovai
#include <cstdio>
#include "processor/contained_range_map-inl.h"
#define ASSERT_TRUE(condition) \
if (!(condition)) { \
fprintf(stderr, "FAIL: %s @ %s:%d\n", #condition, __FILE__, __LINE__); \
return false; \
}
#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))
using google_airbag::ContainedRangeMap;
static bool RunTests() {
ContainedRangeMap<unsigned int, int> crm;
// First, do the StoreRange tests. This validates the containment
// rules.
ASSERT_TRUE (crm.StoreRange(10, 10, 1));
ASSERT_FALSE(crm.StoreRange(10, 10, 2)); // exactly equal to 1
ASSERT_FALSE(crm.StoreRange(11, 10, 3)); // begins inside 1 and extends up
ASSERT_FALSE(crm.StoreRange( 9, 10, 4)); // begins below 1 and ends inside
ASSERT_TRUE (crm.StoreRange(11, 9, 5)); // contained by existing
ASSERT_TRUE (crm.StoreRange(12, 7, 6));
ASSERT_TRUE (crm.StoreRange( 9, 12, 7)); // contains existing
ASSERT_TRUE (crm.StoreRange( 9, 13, 8));
ASSERT_TRUE (crm.StoreRange( 8, 14, 9));
ASSERT_TRUE (crm.StoreRange(30, 3, 10));
ASSERT_TRUE (crm.StoreRange(33, 3, 11));
ASSERT_TRUE (crm.StoreRange(30, 6, 12)); // storable but totally masked
ASSERT_TRUE (crm.StoreRange(40, 8, 13)); // will be totally masked
ASSERT_TRUE (crm.StoreRange(40, 4, 14));
ASSERT_TRUE (crm.StoreRange(44, 4, 15));
ASSERT_FALSE(crm.StoreRange(32, 10, 16)); // begins in #10, ends in #14
ASSERT_FALSE(crm.StoreRange(50, 0, 17)); // zero length
ASSERT_TRUE (crm.StoreRange(50, 10, 18));
ASSERT_TRUE (crm.StoreRange(50, 1, 19));
ASSERT_TRUE (crm.StoreRange(59, 1, 20));
ASSERT_TRUE (crm.StoreRange(60, 1, 21));
ASSERT_TRUE (crm.StoreRange(69, 1, 22));
ASSERT_TRUE (crm.StoreRange(60, 10, 23));
ASSERT_TRUE (crm.StoreRange(68, 1, 24));
ASSERT_TRUE (crm.StoreRange(61, 1, 25));
ASSERT_TRUE (crm.StoreRange(61, 8, 26));
ASSERT_FALSE(crm.StoreRange(59, 9, 27));
ASSERT_FALSE(crm.StoreRange(59, 10, 28));
ASSERT_FALSE(crm.StoreRange(59, 11, 29));
ASSERT_TRUE (crm.StoreRange(70, 10, 30));
ASSERT_TRUE (crm.StoreRange(74, 2, 31));
ASSERT_TRUE (crm.StoreRange(77, 2, 32));
ASSERT_FALSE(crm.StoreRange(72, 6, 33));
ASSERT_TRUE (crm.StoreRange(80, 3, 34));
ASSERT_TRUE (crm.StoreRange(81, 1, 35));
ASSERT_TRUE (crm.StoreRange(82, 1, 36));
ASSERT_TRUE (crm.StoreRange(83, 3, 37));
ASSERT_TRUE (crm.StoreRange(84, 1, 38));
ASSERT_TRUE (crm.StoreRange(83, 1, 39));
ASSERT_TRUE (crm.StoreRange(86, 5, 40));
ASSERT_TRUE (crm.StoreRange(88, 1, 41));
ASSERT_TRUE (crm.StoreRange(90, 1, 42));
ASSERT_TRUE (crm.StoreRange(86, 1, 43));
ASSERT_TRUE (crm.StoreRange(87, 1, 44));
ASSERT_TRUE (crm.StoreRange(89, 1, 45));
ASSERT_TRUE (crm.StoreRange(87, 4, 46));
ASSERT_TRUE (crm.StoreRange(87, 3, 47));
ASSERT_FALSE(crm.StoreRange(86, 2, 48));
// Each element in test_data contains the expected result when calling
// RetrieveRange on an address.
const int test_data[] = {
0, // 0
0, // 1
0, // 2
0, // 3
0, // 4
0, // 5
0, // 6
0, // 7
9, // 8
7, // 9
1, // 10
5, // 11
6, // 12
6, // 13
6, // 14
6, // 15
6, // 16
6, // 17
6, // 18
5, // 19
7, // 20
8, // 21
0, // 22
0, // 23
0, // 24
0, // 25
0, // 26
0, // 27
0, // 28
0, // 29
10, // 30
10, // 31
10, // 32
11, // 33
11, // 34
11, // 35
0, // 36
0, // 37
0, // 38
0, // 39
14, // 40
14, // 41
14, // 42
14, // 43
15, // 44
15, // 45
15, // 46
15, // 47
0, // 48
0, // 49
19, // 50
18, // 51
18, // 52
18, // 53
18, // 54
18, // 55
18, // 56
18, // 57
18, // 58
20, // 59
21, // 60
25, // 61
26, // 62
26, // 63
26, // 64
26, // 65
26, // 66
26, // 67
24, // 68
22, // 69
30, // 70
30, // 71
30, // 72
30, // 73
31, // 74
31, // 75
30, // 76
32, // 77
32, // 78
30, // 79
34, // 80
35, // 81
36, // 82
39, // 83
38, // 84
37, // 85
43, // 86
44, // 87
41, // 88
45, // 89
42, // 90
0, // 91
0, // 92
0, // 93
0, // 94
0, // 95
0, // 96
0, // 97
0, // 98
0 // 99
};
unsigned int test_high = sizeof(test_data) / sizeof(int);
// Now, do the RetrieveRange tests. This further validates that the
// objects were stored properly and that retrieval returns the correct
// object.
// If GENERATE_TEST_DATA is defined, instead of the retrieval tests, a
// new test_data array will be printed. Exercise caution when doing this.
// Be sure to verify the results manually!
#ifdef GENERATE_TEST_DATA
printf(" const int test_data[] = {\n");
#endif // GENERATE_TEST_DATA
for (unsigned int address = 0; address < test_high; ++address) {
int value;
if (!crm.RetrieveRange(address, &value))
value = 0;
#ifndef GENERATE_TEST_DATA
// Don't use ASSERT inside the loop because it won't show the failed
// |address|, and the line number will always be the same. That makes
// it difficult to figure out which test failed.
if (value != test_data[address]) {
fprintf(stderr, "FAIL: retrieve %d expected %d observed %d @ %s:%d\n",
address, test_data[address], value, __FILE__, __LINE__);
return false;
}
#else // !GENERATE_TEST_DATA
printf(" %d%c%s // %d\n", value,
address == test_high - 1 ? ' ' : ',',
value < 10 ? " " : "",
address);
#endif // !GENERATE_TEST_DATA
}
#ifdef GENERATE_TEST_DATA
printf(" };\n");
#endif // GENERATE_TEST_DATA
return true;
}
int main(int argc, char **argv) {
return RunTests() ? 0 : 1;
}

View file

@ -38,6 +38,7 @@ typedef SSIZE_T ssize_t;
#include <vector>
#include "processor/minidump.h"
#include "processor/range_map-inl.h"
namespace google_airbag {

View file

@ -0,0 +1,101 @@
// Copyright (C) 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// range_map-inl.h: Range map implementation.
//
// See range_map.h for documentation.
//
// Author: Mark Mentovai
#ifndef PROCESSOR_RANGE_MAP_INL_H__
#define PROCESSOR_RANGE_MAP_INL_H__
#include "processor/range_map.h"
namespace google_airbag {
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
const AddressType &size,
const EntryType &entry) {
AddressType high = base + size - 1;
// Check for undersize or overflow.
if (size <= 0 || high < base)
return false;
// Ensure that this range does not overlap with another one already in the
// map.
MapConstIterator iterator_base = map_.lower_bound(base);
MapConstIterator iterator_high = map_.lower_bound(high);
if (iterator_base != iterator_high) {
// Some other range begins in the space used by this range. It may be
// contained within the space used by this range, or it may extend lower.
// Regardless, it is an error.
return false;
}
if (iterator_high != map_.end()) {
if (iterator_high->second.base() <= high) {
// The range above this one overlaps with this one. It may fully
// contain this range, or it may begin within this range and extend
// higher. Regardless, it's an error.
return false;
}
}
// Store the range in the map by its high address, so that lower_bound can
// be used to quickly locate a range by address.
map_.insert(MapValue(high, Range(base, entry)));
return true;
}
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::RetrieveRange(
const AddressType &address, EntryType *entry) const {
if (!entry)
return false;
MapConstIterator iterator = map_.lower_bound(address);
if (iterator == map_.end())
return false;
// The map is keyed by the high address of each range, so |address| is
// guaranteed to be lower than the range's high address. If |range| is
// not directly preceded by another range, it's possible for address to
// be below the range's low address, though. When that happens, address
// references something not within any range, so return false.
if (address < iterator->second.base())
return false;
*entry = iterator->second.entry();
return true;
}
template<typename AddressType, typename EntryType>
void RangeMap<AddressType, EntryType>::Clear() {
map_.clear();
}
} // namespace google_airbag
#endif // PROCESSOR_RANGE_MAP_INL_H__

View file

@ -72,81 +72,14 @@ class RangeMap {
// Convenience types.
typedef std::map<AddressType, Range> AddressToRangeMap;
typedef typename AddressToRangeMap::const_iterator const_iterator;
typedef typename AddressToRangeMap::value_type value_type;
typedef typename AddressToRangeMap::const_iterator MapConstIterator;
typedef typename AddressToRangeMap::value_type MapValue;
// Maps the high address of each range to a EntryType.
AddressToRangeMap map_;
};
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
const AddressType &size,
const EntryType &entry) {
AddressType high = base + size - 1;
// Check for undersize or overflow.
if (size <= 0 || high < base)
return false;
// Ensure that this range does not overlap with another one already in the
// map.
const_iterator iterator_base = map_.lower_bound(base);
const_iterator iterator_high = map_.lower_bound(high);
if (iterator_base != iterator_high) {
// Some other range begins in the space used by this range. It may be
// contained within the space used by this range, or it may extend lower.
// Regardless, it is an error.
return false;
}
if (iterator_high != map_.end()) {
if (iterator_high->second.base() <= high) {
// The range above this one overlaps with this one. It may fully
// contain this range, or it may begin within this range and extend
// higher. Regardless, it's an error.
return false;
}
}
// Store the range in the map by its high address, so that lower_bound can
// be used to quickly locate a range by address.
map_.insert(value_type(high, Range(base, entry)));
return true;
}
template<typename AddressType, typename EntryType>
bool RangeMap<AddressType, EntryType>::RetrieveRange(
const AddressType &address, EntryType *entry) const {
if (!entry)
return false;
const_iterator iterator = map_.lower_bound(address);
if (iterator == map_.end())
return false;
// The map is keyed by the high address of each range, so |address| is
// guaranteed to be lower than the range's high address. If |range| is
// not directly preceded by another range, it's possible for address to
// be below the range's low address, though. When that happens, address
// references something not within any range, so return false.
if (address < iterator->second.base())
return false;
*entry = iterator->second.entry();
return true;
}
template<typename AddressType, typename EntryType>
void RangeMap<AddressType, EntryType>::Clear() {
map_.clear();
}
} // namespace google_airbag

View file

@ -21,7 +21,7 @@
#include <cstdio>
#include <memory>
#include "processor/range_map.h"
#include "processor/range_map-inl.h"
using std::auto_ptr;

View file

@ -20,7 +20,7 @@
#include "processor/source_line_resolver.h"
#include "google/stack_frame.h"
#include "processor/linked_ptr.h"
#include "processor/range_map.h"
#include "processor/range_map-inl.h"
using std::map;
using std::vector;