libcwd: The C++ Debugging Support Library - Reference Manual
Author: Carlo Wood
Description: C++ debugging support library with ostream debug output
Keywords: libcwd, debug output, debug facility, debug channel, object orientation, OO, C++, nested debug output, ostream, memory allocation, debugging, source file and line number

Main Page Reference Manual Namespace List Compound List Namespace Members Compound Members File Members

# libcwd/class_function.h

Go to the documentation of this file.

    00001 // $Header$
    00002 //
    00003 // Copyright (C) 2003 - 2004, by
    00004 //
    00005 // Carlo Wood, Run on IRC <carlo@alinoe.com>
    00006 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
    00007 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
    00008 //
    00009 // This file may be distributed under the terms of the Q Public License
    00010 // version 1.0 as appearing in the file LICENSE.QPL included in the
    00011 // packaging of this file.
    00012 //
    00013
    00018 #ifndef LIBCWD_CLASS_FUNCTION_H
    00019 #define LIBCWD_CLASS_FUNCTION_H
    00020
    00021 #ifndef LIBCW_MAP
    00022 #define LIBCW_MAP
    00023 #include <map>
    00024 #endif
    00025
    00026 namespace libcwd {
    00027
    00028 namespace _private_ {
    00029
    00030 // A FunctionChunk represents a contiguous area of code generated by the source
    00031 // of a single function, excluding its inlined functions.  The FunctionChunkKey defines
    00032 // the begin and end address of the chunk.  A function chunk can therefore begin or
    00033 // end at the real function begin or end, but also at the end of, or the beginning of,
    00034 // a piece of code that belongs to an inlined function.  As a result, every memory
    00035 // address belongs to at most one FunctionChunk.
    00036
    00037 struct FunctionChunkKey {
    00038   void const* M_start;          // The first byte of the chunk.
    00039   void const* M_end;            // One past the last byte of the chunk.
    00040 };
    00041
    00042 // A FunctionChunk represents a contiguous area of code generated by the source
    00043 // of a single function.
    00044
    00045 class FunctionInstance;         // Forward declaration.
    00046 typedef std::pair<FunctionChunkKey const, FunctionInstance*> FunctionChunk;
    00047                                 // This is the value type of the chunk map (FunctionInstanceMap::value_type).
    00048
    00049 // Function chunks will never overlap in the end, but while attempting to add
    00050 // a new area to the chunk map it is possible that we find that an existing
    00051 // chunk overlaps with one that we try to add because we first added the
    00052 // outer function and then try to add an inlined function.
    00053 //
    00054 // by defining the operator<() for FunctionChunkKey's as follows, two overlapping
    00055 // chunks A and B:
    00056 //
    00057 //    M_start                         M_end
    00058 // A:  |-------------------------------|
    00059 // B:         |----------|
    00060 //           M_start    M_end
    00061 //
    00062 // will return `false' for both (A < B) and (B < A).
    00063 // As a result, the chunk map<> will consider them to be equal and not
    00064 // insert an overlapping chunk, but notify us of the overlap instead.
    00065
    00066 inline bool
    00067 operator<(FunctionChunkKey const& chunk1, FunctionChunkKey const& chunk2)
    00068 {
    00069   // Chunks of size 0 do not exist; therefore it is safe to use the equal sign here.
    00070   return chunk1.M_end <= chunk2.M_start;
    00071 }
    00072
    00073 // A FunctionRootInstanceKey is used as key in FunctionRootsMap in order to garantee
    00074 // uniqueness of the FunctionRootInstance objects.
    00075
    00076 struct FunctionRootInstanceKey {
    00077   char const* M_mangled_name;           // The mangled name is what makes a root instance unique because we
    00078                                         // only keep functions from the a single compilation unit per map.
    00079                                         // See class compilation_unit_ct.
    00080 };
    00081
    00082 // A sorting algorithm for this key.
    00083
    00084 inline bool
    00085 operator<(FunctionRootInstanceKey key1, FunctionRootInstanceKey key2)
    00086 {
    00087   return std::strcmp(key1.M_mangled_name, key2.M_mangled_name);
    00088 }
    00089
    00090 // A FunctionRootInstance represents the root instance of a function: it is not
    00091 // an inlined instantiation but the standalone version of a function.
    00092 //
    00093 // All function roots are stored in a map functionRootsMap of type
    00094 // map<FunctionRootInstanceKey, FunctionRootInstanceInfo>, see below.
    00095 // The FunctionRootInstance contains images of all its instantiations,
    00096 // so there should be only one copy of it.  The canonical copy is at
    00097 // all times the instance that is added to the functionRootsMap.
    00098
    00099 class FunctionRootInstanceInfo;         // Forward declaration.
    00100 typedef std::pair<FunctionRootInstanceKey const, FunctionRootInstanceInfo> FunctionRootInstance;
    00101                                 // This is the value type of the function roots map (FunctionRootsMap::value_type).
    00102
    00103 // A FunctionInstance represents an instantiation of a function, whether inlined
    00104 // or not.  As a result, a FunctionInstance belongs to precisely one memory area,
    00105 // but a single memory address can belong to multiple FunctionInstances when
    00106 // it belongs to a chunk of an inlined function:
    00107 //
    00108 //                              <--program address space-->
    00109 //                            low_pc                                      high_pc
    00110 // FunctionInstance f:         |--------------------------------------------|
    00111 //                                     low_pc     high_pc
    00112 // Inlined FunctionInstance g:          |-----------|
    00113 //
    00114 // Three function chunks:      |ffffffff|ggggggggggg|fffffffffffffffffffffff|
    00115 //                                          ^
    00116 //                                          x
    00117 // Address 'x' belongs to a single chunk, but to two FunctionInstance's.
    00118
    00119 class FunctionInstance {
    00120 private:
    00121   void const* M_lowpc;                  // The low_pc of the function instance.
    00122   void const* M_highpc;                 // The high_pc of the function instance.
    00123   FunctionRootInstance* M_root;         // Pointer to the root definition of this function.
    00124   FunctionInstance* M_inlined_by;       // Pointer to the function instance that contains this
    00125                                         // inlined function, or NULL when this is a root definition.
    00126 public:
    00127   FunctionInstance(void const* lowpc, void const* highpc, FunctionRootInstance* root, FunctionInstance* inlined_by) :
    00128       M_lowpc(lowpc), M_highpc(highpc), M_root(root), M_inlined_by(inlined_by) { }
    00129
    00130   void const* lowpc(void) const { return M_lowpc; }
    00131   void const* highpc(void) const { return M_highpc; }
    00132   inline FunctionRootInstance const* root(void) const;
    00133   inline FunctionInstance const* inlined_by(void) const;
    00134 };
    00135
    00136 // The functionChunkMap contains a mapping of every memory address to the
    00137 // function responsible for the assembly code at that address.
    00138 //
    00139 // Chunks may not overlap.  When trying to insert a chunk that overlaps
    00140 // with an existing chunk, insert() will return a pair<..., bool> with
    00141 // the boolean set to false.
    00142
    00143 #if CWDEBUG_ALLOC
    00144 typedef std::map<FunctionChunkKey, FunctionInstance*, std::less<FunctionChunkKey>,
    00145     _private_::internal_allocator::rebind<FunctionChunk>::other> FunctionChunkMap;
    00146 #else
    00147 typedef std::map<FunctionChunkKey, FunctionInstance*, std::less<FunctionChunkKey> > FunctionChunkMap;
    00148 #endif
    00149 extern FunctionChunkMap functionChunkMap;
    00150
    00151 // The remaining information for the function root instance.
    00152
    00153 class FunctionRootInstanceInfo {
    00154 private:
    00155   FunctionInstance M_instance;                          // The root instance itself.
    00156   std::string M_demangled_name;                         // The demangled name of this function.
    00157   std::vector<FunctionInstance> M_inlined_instances;    // All the inlined instances.
    00158
    00159 public:
    00160   FunctionRootInstanceInfo(void const* lowpc, void const* highpc, std::string const& demangled_name);
    00161   void const* lowpc(void) const { return M_instance.lowpc(); }
    00162   void const* highpc(void) const { return M_instance.highpc(); }
    00163   std::string const& demangled_name(void) const { return M_demangled_name; }
    00164   std::vector<FunctionInstance> const& inlined_instances(void) const { return M_inlined_instances; }
    00165   std::vector<FunctionInstance>& inlined_instances(void) { return M_inlined_instances; }
    00166 };
    00167
    00168 // The functionRootsMap contains all function roots.  The key used is the mangled name
    00169 // of the function, causing each function root to be added to the map at most once.
    00170
    00171 #if CWDEBUG_ALLOC
    00172 typedef std::map<FunctionRootInstanceKey, FunctionRootInstanceInfo, std::less<FunctionRootInstanceKey>,
    00173     _private_::internal_allocator::rebind<FunctionRootInstance>::other> FunctionRootsMap;
    00174 #else
    00175 typedef std::map<FunctionRootInstanceKey, FunctionRootInstanceInfo, std::less<FunctionRootInstanceKey> > FunctionRootsMap;
    00176 #endif
    00177
    00178 FunctionRootInstance const*
    00179 FunctionInstance::root(void) const
    00180 {
    00181   return M_root;
    00182 }
    00183
    00184 FunctionInstance const*
    00185 FunctionInstance::inlined_by(void) const
    00186 {
    00187   return M_inlined_by;
    00188 }
    00189
    00190 } // namespace _private_
    00191
    00192 // The Function object represents a function and is intended to be
    00193 // used by the user to designate a particular function.  Whether or not
    00194 // the function is inlined is completely shielded from the user at
    00195 // this point.
    00196
    00197 class Function {
    00198 private:
    00199   int volatile M_initialized;
    00200   unsigned int M_flags;
    00201
    00202   _private_::FunctionRootInstance* M_root;
    00203   char const* M_label;
    00204
    00205 public:
    00206   char const* label(void) const { return M_label; }
    00207   bool is_initialized(void) const { return M_initialized; }
    00208
    00209 private:
    00210   void M_init(void);
    00211   void M_init(Function& function);
    00212   void M_init(char const* expr, unsigned int flags);
    00213
    00214 public:
    00215   static unsigned int const nofail = 1;
    00216   static unsigned int const c_linkage = 2;
    00217   static unsigned int const cpp_linkage = 4;
    00218   static unsigned int const mangled = 8;
    00219   static unsigned int const regexp = 16;
    00220   static unsigned int const exactmatch = 32;
    00221
    00222   Function(void) : M_initialized(false), M_flags(0) { }
    00223   Function(unsigned int flags) : M_initialized(false), M_flags(flags) { }
    00224
    00225   void init(void) { if (!M_initialized) M_init(); }
    00226   void init(Function& function) { if (!function.is_initialized()) M_init(function); }
    00227   void init(char const* expr, unsigned int flags = mangled|cpp_linkage) { if (!M_initialized) M_init(expr, flags); }
    00228
    00229   void label(char const* lbl) { M_label = lbl; }
    00230   void rmlabel(void) { M_label = NULL; }
    00231 };
    00232
    00233 } // namespace libcwd
    00234
    00235 #endif // LIBCWD_CLASS_FUNCTION_H