Home | History | Annotate | Line # | Download | only in libunwind
      1   1.1     joerg //===------------------------- AddressSpace.hpp ---------------------------===//
      2   1.1     joerg //
      3   1.1     joerg //                     The LLVM Compiler Infrastructure
      4   1.1     joerg //
      5   1.1     joerg // This file is dual licensed under the MIT and the University of Illinois Open
      6   1.1     joerg // Source Licenses. See LICENSE.TXT for details.
      7   1.1     joerg //
      8   1.1     joerg //
      9   1.1     joerg // Abstracts accessing local vs remote address spaces.
     10   1.1     joerg //
     11   1.1     joerg //===----------------------------------------------------------------------===//
     12   1.1     joerg 
     13   1.1     joerg #ifndef __ADDRESSSPACE_HPP__
     14   1.1     joerg #define __ADDRESSSPACE_HPP__
     15   1.1     joerg 
     16   1.1     joerg #include <sys/rbtree.h>
     17   1.1     joerg #include <cassert>
     18   1.1     joerg #include <cstddef>
     19   1.1     joerg #include <cstdint>
     20   1.1     joerg #include <cstdlib>
     21   1.1     joerg #include <cstring>
     22   1.1     joerg #include <dlfcn.h>
     23   1.1     joerg #include <elf.h>
     24   1.1     joerg #include <link.h>
     25   1.1     joerg #include <pthread.h>
     26   1.1     joerg 
     27   1.1     joerg #include "dwarf2.h"
     28   1.1     joerg 
     29   1.1     joerg namespace _Unwind {
     30   1.1     joerg 
     31   1.1     joerg static int rangeCmp(void *, const void *, const void *);
     32   1.1     joerg static int rangeCmpKey(void *, const void *, const void *);
     33   1.1     joerg static int dsoTableCmp(void *, const void *, const void *);
     34   1.1     joerg static int dsoTableCmpKey(void *, const void *, const void *);
     35   1.1     joerg static int phdr_callback(struct dl_phdr_info *, size_t, void *);
     36   1.1     joerg 
     37   1.1     joerg struct unw_proc_info_t {
     38   1.1     joerg   uintptr_t data_base;       // Base address for data-relative relocations
     39   1.1     joerg   uintptr_t start_ip;        // Start address of function
     40   1.1     joerg   uintptr_t end_ip;          // First address after end of function
     41   1.1     joerg   uintptr_t lsda;            // Address of Language Specific Data Area
     42   1.1     joerg   uintptr_t handler;         // Personality routine
     43   1.1     joerg   uintptr_t extra_args;      // Extra stack space for frameless routines
     44   1.1     joerg   uintptr_t unwind_info;     // Address of DWARF unwind info
     45   1.1     joerg };
     46   1.1     joerg 
     47   1.1     joerg /// LocalAddressSpace is used as a template parameter to UnwindCursor when
     48   1.1     joerg /// unwinding a thread in the same process.  The wrappers compile away,
     49   1.1     joerg /// making local unwinds fast.
     50   1.1     joerg class LocalAddressSpace {
     51   1.1     joerg public:
     52   1.1     joerg   typedef uintptr_t pint_t;
     53   1.1     joerg   typedef intptr_t sint_t;
     54   1.1     joerg 
     55   1.1     joerg   typedef void (*findPCRange_t)(LocalAddressSpace &, pint_t, pint_t &pcStart,
     56   1.1     joerg                                 pint_t &pcEnd);
     57   1.1     joerg 
     58   1.1     joerg   LocalAddressSpace(findPCRange_t findPCRange_)
     59   1.1     joerg       : findPCRange(findPCRange_), needsReload(true) {
     60   1.1     joerg     static const rb_tree_ops_t segmentTreeOps = {
     61   1.1     joerg       rangeCmp, rangeCmpKey, offsetof(Range, range_link), NULL
     62   1.1     joerg     };
     63   1.1     joerg     static const rb_tree_ops_t dsoTreeOps = {
     64   1.1     joerg       dsoTableCmp, dsoTableCmpKey, offsetof(Range, dso_link), NULL
     65   1.1     joerg     };
     66   1.1     joerg     rb_tree_init(&segmentTree, &segmentTreeOps);
     67   1.1     joerg     rb_tree_init(&dsoTree, &dsoTreeOps);
     68   1.1     joerg     pthread_rwlock_init(&fdeTreeLock, NULL);
     69   1.1     joerg   }
     70   1.1     joerg 
     71   1.4     joerg   uint8_t get8(pint_t addr) {
     72   1.4     joerg     uint8_t val;
     73   1.4     joerg     memcpy(&val, (void *)addr, sizeof(val));
     74   1.4     joerg     return val;
     75   1.4     joerg   }
     76   1.1     joerg 
     77   1.4     joerg   uint16_t get16(pint_t addr) {
     78   1.4     joerg     uint16_t val;
     79   1.4     joerg     memcpy(&val, (void *)addr, sizeof(val));
     80   1.4     joerg     return val;
     81   1.4     joerg   }
     82   1.1     joerg 
     83   1.4     joerg   uint32_t get32(pint_t addr) {
     84   1.4     joerg     uint32_t val;
     85   1.4     joerg     memcpy(&val, (void *)addr, sizeof(val));
     86   1.4     joerg     return val;
     87   1.4     joerg   }
     88   1.1     joerg 
     89   1.4     joerg   uint64_t get64(pint_t addr) {
     90   1.4     joerg     uint64_t val;
     91   1.4     joerg     memcpy(&val, (void *)addr, sizeof(val));
     92   1.4     joerg     return val;
     93   1.4     joerg   }
     94   1.1     joerg 
     95   1.1     joerg   uintptr_t getP(pint_t addr) {
     96   1.1     joerg     if (sizeof(uintptr_t) == sizeof(uint32_t))
     97   1.1     joerg       return get32(addr);
     98   1.1     joerg     else
     99   1.1     joerg       return get64(addr);
    100   1.1     joerg   }
    101   1.1     joerg 
    102   1.1     joerg   uint64_t getULEB128(pint_t &addr, pint_t end) {
    103   1.1     joerg     uint64_t result = 0;
    104   1.1     joerg     uint8_t byte;
    105   1.1     joerg     int bit = 0;
    106   1.1     joerg     do {
    107   1.1     joerg       uint64_t b;
    108   1.1     joerg 
    109   1.1     joerg       assert(addr != end);
    110   1.1     joerg 
    111   1.1     joerg       byte = get8(addr++);
    112   1.1     joerg       b = byte & 0x7f;
    113   1.1     joerg 
    114   1.1     joerg       assert(bit < 64);
    115   1.1     joerg       assert(b << bit >> bit == b);
    116   1.1     joerg 
    117   1.1     joerg       result |= b << bit;
    118   1.1     joerg       bit += 7;
    119   1.1     joerg     } while (byte >= 0x80);
    120   1.1     joerg     return result;
    121   1.1     joerg   }
    122   1.1     joerg 
    123   1.1     joerg   int64_t getSLEB128(pint_t &addr, pint_t end) {
    124   1.1     joerg     uint64_t result = 0;
    125   1.1     joerg     uint8_t byte;
    126   1.1     joerg     int bit = 0;
    127   1.1     joerg     do {
    128   1.1     joerg       uint64_t b;
    129   1.1     joerg 
    130   1.1     joerg       assert(addr != end);
    131   1.1     joerg 
    132   1.1     joerg       byte = get8(addr++);
    133   1.1     joerg       b = byte & 0x7f;
    134   1.1     joerg 
    135   1.1     joerg       assert(bit < 64);
    136   1.1     joerg       assert(b << bit >> bit == b);
    137   1.1     joerg 
    138   1.1     joerg       result |= b << bit;
    139   1.1     joerg       bit += 7;
    140   1.1     joerg     } while (byte >= 0x80);
    141   1.1     joerg     // sign extend negative numbers
    142   1.1     joerg     if ((byte & 0x40) != 0)
    143   1.9  christos       result |= (~0ULL) << bit;
    144   1.1     joerg     return result;
    145   1.1     joerg   }
    146   1.1     joerg 
    147   1.1     joerg   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
    148   1.1     joerg                      const unw_proc_info_t *ctx) {
    149   1.1     joerg     pint_t startAddr = addr;
    150   1.1     joerg     const uint8_t *p = (uint8_t *)addr;
    151   1.1     joerg     pint_t result;
    152   1.1     joerg 
    153   1.1     joerg     if (encoding == DW_EH_PE_omit)
    154   1.1     joerg       return 0;
    155   1.1     joerg     if (encoding == DW_EH_PE_aligned) {
    156   1.1     joerg       addr = (addr + sizeof(pint_t) - 1) & sizeof(pint_t);
    157   1.1     joerg       return getP(addr);
    158   1.1     joerg     }
    159   1.1     joerg 
    160   1.1     joerg     // first get value
    161   1.1     joerg     switch (encoding & 0x0F) {
    162   1.1     joerg     case DW_EH_PE_ptr:
    163   1.1     joerg       result = getP(addr);
    164   1.1     joerg       p += sizeof(pint_t);
    165   1.1     joerg       addr = (pint_t)p;
    166   1.1     joerg       break;
    167   1.1     joerg     case DW_EH_PE_uleb128:
    168   1.1     joerg       result = getULEB128(addr, end);
    169   1.1     joerg       break;
    170   1.1     joerg     case DW_EH_PE_udata2:
    171   1.1     joerg       result = get16(addr);
    172   1.1     joerg       p += 2;
    173   1.1     joerg       addr = (pint_t)p;
    174   1.1     joerg       break;
    175   1.1     joerg     case DW_EH_PE_udata4:
    176   1.1     joerg       result = get32(addr);
    177   1.1     joerg       p += 4;
    178   1.1     joerg       addr = (pint_t)p;
    179   1.1     joerg       break;
    180   1.1     joerg     case DW_EH_PE_udata8:
    181   1.1     joerg       result = get64(addr);
    182   1.1     joerg       p += 8;
    183   1.1     joerg       addr = (pint_t)p;
    184   1.1     joerg       break;
    185   1.1     joerg     case DW_EH_PE_sleb128:
    186   1.1     joerg       result = getSLEB128(addr, end);
    187   1.1     joerg       break;
    188   1.1     joerg     case DW_EH_PE_sdata2:
    189   1.1     joerg       result = (int16_t)get16(addr);
    190   1.1     joerg       p += 2;
    191   1.1     joerg       addr = (pint_t)p;
    192   1.1     joerg       break;
    193   1.1     joerg     case DW_EH_PE_sdata4:
    194   1.1     joerg       result = (int32_t)get32(addr);
    195   1.1     joerg       p += 4;
    196   1.1     joerg       addr = (pint_t)p;
    197   1.1     joerg       break;
    198   1.1     joerg     case DW_EH_PE_sdata8:
    199   1.1     joerg       result = get64(addr);
    200   1.1     joerg       p += 8;
    201   1.1     joerg       addr = (pint_t)p;
    202   1.1     joerg       break;
    203   1.1     joerg     case DW_EH_PE_omit:
    204   1.1     joerg       result = 0;
    205   1.1     joerg       break;
    206   1.1     joerg     default:
    207   1.1     joerg       assert(0 && "unknown pointer encoding");
    208   1.1     joerg     }
    209   1.1     joerg 
    210   1.1     joerg     // then add relative offset
    211   1.1     joerg     switch (encoding & 0x70) {
    212   1.1     joerg     case DW_EH_PE_absptr:
    213   1.1     joerg       // do nothing
    214   1.1     joerg       break;
    215   1.1     joerg     case DW_EH_PE_pcrel:
    216   1.1     joerg       result += startAddr;
    217   1.1     joerg       break;
    218   1.1     joerg     case DW_EH_PE_textrel:
    219   1.1     joerg       assert(0 && "DW_EH_PE_textrel pointer encoding not supported");
    220   1.1     joerg       break;
    221   1.1     joerg     case DW_EH_PE_datarel:
    222   1.1     joerg       assert(ctx != NULL && "DW_EH_PE_datarel without context");
    223   1.1     joerg       if (ctx)
    224   1.1     joerg         result += ctx->data_base;
    225   1.1     joerg       break;
    226   1.1     joerg     case DW_EH_PE_funcrel:
    227   1.1     joerg       assert(ctx != NULL && "DW_EH_PE_funcrel without context");
    228   1.1     joerg       if (ctx)
    229   1.1     joerg         result += ctx->start_ip;
    230   1.1     joerg       break;
    231   1.1     joerg     case DW_EH_PE_aligned:
    232   1.1     joerg       __builtin_unreachable();
    233   1.1     joerg     default:
    234   1.1     joerg       assert(0 && "unknown pointer encoding");
    235   1.1     joerg       break;
    236   1.1     joerg     }
    237   1.1     joerg 
    238   1.1     joerg     if (encoding & DW_EH_PE_indirect)
    239   1.1     joerg       result = getP(result);
    240   1.1     joerg 
    241   1.1     joerg     return result;
    242   1.1     joerg   }
    243   1.1     joerg 
    244   1.1     joerg   bool findFDE(pint_t pc, pint_t &fdeStart, pint_t &data_base) {
    245   1.1     joerg     Range *n;
    246   1.1     joerg     for (;;) {
    247   1.1     joerg       pthread_rwlock_rdlock(&fdeTreeLock);
    248   1.1     joerg       n = (Range *)rb_tree_find_node(&segmentTree, &pc);
    249   1.1     joerg       pthread_rwlock_unlock(&fdeTreeLock);
    250   1.1     joerg       if (n != NULL)
    251   1.1     joerg         break;
    252   1.1     joerg       if (!needsReload)
    253   1.1     joerg         break;
    254   1.1     joerg       lazyReload();
    255   1.1     joerg     }
    256   1.1     joerg     if (n == NULL)
    257   1.1     joerg       return false;
    258   1.1     joerg     if (n->hdr_start == 0) {
    259   1.1     joerg       fdeStart = n->hdr_base;
    260   1.3     joerg       data_base = n->data_base;
    261   1.1     joerg       return true;
    262   1.1     joerg     }
    263   1.1     joerg 
    264   1.1     joerg     pint_t base = n->hdr_base;
    265   1.1     joerg     pint_t first = n->hdr_start;
    266   1.8     joerg     for (pint_t len = n->hdr_entries; len > 1; ) {
    267   1.8     joerg       pint_t next = first + (len / 2) * 8;
    268   1.1     joerg       pint_t nextPC = base + (int32_t)get32(next);
    269   1.1     joerg       if (nextPC == pc) {
    270   1.1     joerg         first = next;
    271   1.1     joerg         break;
    272   1.1     joerg       }
    273   1.1     joerg       if (nextPC < pc) {
    274   1.1     joerg         first = next;
    275   1.8     joerg         len -= (len / 2);
    276   1.8     joerg       } else {
    277   1.8     joerg         len /= 2;
    278   1.8     joerg       }
    279   1.1     joerg     }
    280   1.1     joerg     fdeStart = base + (int32_t)get32(first + 4);
    281   1.3     joerg     data_base = n->data_base;
    282   1.1     joerg     return true;
    283   1.1     joerg   }
    284   1.1     joerg 
    285   1.1     joerg   bool addFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
    286   1.1     joerg     Range *n = (Range *)malloc(sizeof(*n));
    287   1.1     joerg     n->hdr_base = fde;
    288   1.1     joerg     n->hdr_start = 0;
    289   1.1     joerg     n->hdr_entries = 0;
    290   1.1     joerg     n->first_pc = pcStart;
    291   1.1     joerg     n->last_pc = pcEnd;
    292   1.1     joerg     n->data_base = 0;
    293   1.1     joerg     n->ehframe_base = 0;
    294  1.10     joerg     pthread_rwlock_wrlock(&fdeTreeLock);
    295   1.6     joerg     if (static_cast<Range *>(rb_tree_insert_node(&segmentTree, n)) == n) {
    296   1.1     joerg       pthread_rwlock_unlock(&fdeTreeLock);
    297   1.1     joerg       return true;
    298   1.1     joerg     }
    299   1.1     joerg     free(n);
    300   1.1     joerg     pthread_rwlock_unlock(&fdeTreeLock);
    301   1.1     joerg     return false;
    302   1.1     joerg   }
    303   1.1     joerg 
    304   1.1     joerg   bool removeFDE(pint_t pcStart, pint_t pcEnd, pint_t fde) {
    305   1.1     joerg     pthread_rwlock_wrlock(&fdeTreeLock);
    306   1.6     joerg     Range *n = static_cast<Range *>(rb_tree_find_node(&segmentTree, &pcStart));
    307   1.1     joerg     if (n == NULL) {
    308   1.1     joerg       pthread_rwlock_unlock(&fdeTreeLock);
    309   1.1     joerg       return false;
    310   1.1     joerg     }
    311   1.1     joerg     assert(n->first_pc == pcStart);
    312   1.1     joerg     assert(n->last_pc == pcEnd);
    313   1.1     joerg     assert(n->hdr_base == fde);
    314   1.1     joerg     assert(n->hdr_start == 0);
    315   1.1     joerg     assert(n->hdr_entries == 0);
    316   1.1     joerg     assert(n->data_base == 0);
    317   1.1     joerg     assert(n->ehframe_base == 0);
    318   1.1     joerg     rb_tree_remove_node(&segmentTree, n);
    319   1.1     joerg     free(n);
    320   1.1     joerg     pthread_rwlock_unlock(&fdeTreeLock);
    321   1.1     joerg     return true;
    322   1.1     joerg   }
    323   1.1     joerg 
    324   1.1     joerg   void removeDSO(pint_t ehFrameBase) {
    325   1.1     joerg     pthread_rwlock_wrlock(&fdeTreeLock);
    326   1.1     joerg     Range *n;
    327   1.1     joerg     n = (Range *)rb_tree_find_node(&dsoTree, &ehFrameBase);
    328   1.1     joerg     if (n == NULL) {
    329   1.1     joerg       pthread_rwlock_unlock(&fdeTreeLock);
    330   1.1     joerg       return;
    331   1.1     joerg     }
    332   1.1     joerg     rb_tree_remove_node(&dsoTree, n);
    333   1.1     joerg     rb_tree_remove_node(&segmentTree, n);
    334   1.1     joerg     free(n);
    335   1.1     joerg     pthread_rwlock_unlock(&fdeTreeLock);
    336   1.1     joerg   }
    337   1.1     joerg 
    338   1.1     joerg   void setLazyReload() {
    339   1.1     joerg     pthread_rwlock_wrlock(&fdeTreeLock);
    340   1.1     joerg     needsReload = true;
    341   1.1     joerg     pthread_rwlock_unlock(&fdeTreeLock);
    342   1.1     joerg   }
    343   1.1     joerg 
    344   1.1     joerg private:
    345   1.1     joerg   findPCRange_t findPCRange;
    346   1.1     joerg   bool needsReload;
    347   1.1     joerg   pthread_rwlock_t fdeTreeLock;
    348   1.1     joerg   rb_tree_t segmentTree;
    349   1.1     joerg   rb_tree_t dsoTree;
    350   1.1     joerg 
    351   1.1     joerg   friend int phdr_callback(struct dl_phdr_info *, size_t, void *);
    352   1.1     joerg   friend int rangeCmp(void *, const void *, const void *);
    353   1.1     joerg   friend int rangeCmpKey(void *, const void *, const void *);
    354   1.1     joerg   friend int dsoTableCmp(void *, const void *, const void *);
    355   1.1     joerg   friend int dsoTableCmpKey(void *, const void *, const void *);
    356   1.1     joerg 
    357   1.1     joerg   void updateRange();
    358   1.1     joerg 
    359   1.1     joerg   struct Range {
    360   1.1     joerg     rb_node_t range_link;
    361   1.1     joerg     rb_node_t dso_link;
    362   1.1     joerg     pint_t hdr_base; // Pointer to FDE if hdr_start == 0
    363   1.1     joerg     pint_t hdr_start;
    364   1.1     joerg     pint_t hdr_entries;
    365   1.1     joerg     pint_t first_pc;
    366   1.1     joerg     pint_t last_pc;
    367   1.1     joerg     pint_t data_base;
    368   1.1     joerg     pint_t ehframe_base;
    369   1.1     joerg   };
    370   1.1     joerg 
    371   1.1     joerg   void lazyReload() {
    372   1.1     joerg     pthread_rwlock_wrlock(&fdeTreeLock);
    373   1.1     joerg     dl_iterate_phdr(phdr_callback, this);
    374   1.1     joerg     needsReload = false;
    375   1.1     joerg     pthread_rwlock_unlock(&fdeTreeLock);
    376   1.1     joerg   }
    377   1.1     joerg 
    378   1.1     joerg   void addDSO(pint_t header, pint_t data_base) {
    379   1.1     joerg     if (header == 0)
    380   1.1     joerg       return;
    381   1.1     joerg     if (get8(header) != 1)
    382   1.1     joerg       return;
    383   1.1     joerg     if (get8(header + 3) != (DW_EH_PE_datarel | DW_EH_PE_sdata4))
    384   1.1     joerg       return;
    385   1.1     joerg     pint_t end = header + 4;
    386   1.1     joerg     pint_t ehframe_base = getEncodedP(end, 0, get8(header + 1), NULL);
    387   1.1     joerg     pint_t entries = getEncodedP(end, 0, get8(header + 2), NULL);
    388   1.1     joerg     pint_t start = (end + 3) & ~pint_t(3);
    389   1.1     joerg     if (entries == 0)
    390   1.1     joerg       return;
    391   1.1     joerg     Range *n = (Range *)malloc(sizeof(*n));
    392   1.1     joerg     n->hdr_base = header;
    393   1.1     joerg     n->hdr_start = start;
    394   1.1     joerg     n->hdr_entries = entries;
    395   1.1     joerg     n->first_pc = header + (int32_t)get32(n->hdr_start);
    396   1.1     joerg     pint_t tmp;
    397   1.1     joerg     (*findPCRange)(
    398   1.1     joerg         *this, header + (int32_t)get32(n->hdr_start + (entries - 1) * 8 + 4),
    399   1.1     joerg         tmp, n->last_pc);
    400   1.1     joerg     n->data_base = data_base;
    401   1.1     joerg     n->ehframe_base = ehframe_base;
    402   1.1     joerg 
    403   1.7     joerg     if (static_cast<Range *>(rb_tree_insert_node(&segmentTree, n)) != n) {
    404   1.1     joerg       free(n);
    405   1.1     joerg       return;
    406   1.1     joerg     }
    407   1.1     joerg     rb_tree_insert_node(&dsoTree, n);
    408   1.1     joerg   }
    409   1.1     joerg };
    410   1.1     joerg 
    411   1.1     joerg static int phdr_callback(struct dl_phdr_info *info, size_t size, void *data_) {
    412   1.1     joerg   LocalAddressSpace *data = (LocalAddressSpace *)data_;
    413   1.1     joerg   size_t eh_frame = 0, data_base = 0;
    414   1.1     joerg   const Elf_Phdr *hdr = info->dlpi_phdr;
    415   1.1     joerg   const Elf_Phdr *last_hdr = hdr + info->dlpi_phnum;
    416   1.1     joerg   const Elf_Dyn *dyn;
    417   1.1     joerg 
    418   1.1     joerg   for (; hdr != last_hdr; ++hdr) {
    419   1.1     joerg     switch (hdr->p_type) {
    420   1.1     joerg     case PT_GNU_EH_FRAME:
    421   1.1     joerg       eh_frame = info->dlpi_addr + hdr->p_vaddr;
    422   1.1     joerg       break;
    423   1.1     joerg     case PT_DYNAMIC:
    424   1.1     joerg       dyn = (const Elf_Dyn *)(info->dlpi_addr + hdr->p_vaddr);
    425   1.1     joerg       while (dyn->d_tag != DT_NULL) {
    426   1.1     joerg         if (dyn->d_tag == DT_PLTGOT) {
    427   1.1     joerg           data_base = info->dlpi_addr + dyn->d_un.d_ptr;
    428   1.1     joerg           break;
    429   1.1     joerg         }
    430   1.1     joerg         ++dyn;
    431   1.1     joerg       }
    432   1.1     joerg     }
    433   1.1     joerg   }
    434   1.1     joerg 
    435   1.1     joerg   if (eh_frame)
    436   1.1     joerg     data->addDSO(eh_frame, data_base);
    437   1.1     joerg 
    438   1.1     joerg   return 0;
    439   1.1     joerg }
    440   1.1     joerg 
    441   1.1     joerg static int rangeCmp(void *context, const void *n1_, const void *n2_) {
    442   1.2     joerg   const LocalAddressSpace::Range *n1 = (const LocalAddressSpace::Range *)n1_;
    443   1.2     joerg   const LocalAddressSpace::Range *n2 = (const LocalAddressSpace::Range *)n2_;
    444   1.1     joerg 
    445   1.1     joerg   if (n1->first_pc < n2->first_pc)
    446   1.1     joerg     return -1;
    447   1.1     joerg   if (n1->first_pc > n2->first_pc)
    448   1.1     joerg     return 1;
    449   1.1     joerg   assert(n1->last_pc == n2->last_pc);
    450   1.1     joerg   return 0;
    451   1.1     joerg }
    452   1.1     joerg 
    453   1.1     joerg static int rangeCmpKey(void *context, const void *n_, const void *pc_) {
    454   1.2     joerg   const LocalAddressSpace::Range *n = (const LocalAddressSpace::Range *)n_;
    455   1.2     joerg   const LocalAddressSpace::pint_t *pc = (const LocalAddressSpace::pint_t *)pc_;
    456   1.1     joerg   if (n->last_pc < *pc)
    457   1.1     joerg     return -1;
    458   1.1     joerg   if (n->first_pc > *pc)
    459   1.1     joerg     return 1;
    460   1.1     joerg   return 0;
    461   1.1     joerg }
    462   1.1     joerg 
    463   1.1     joerg static int dsoTableCmp(void *context, const void *n1_, const void *n2_) {
    464   1.2     joerg   const LocalAddressSpace::Range *n1 = (const LocalAddressSpace::Range *)n1_;
    465   1.2     joerg   const LocalAddressSpace::Range *n2 = (const LocalAddressSpace::Range *)n2_;
    466   1.1     joerg 
    467   1.1     joerg   if (n1->ehframe_base < n2->ehframe_base)
    468   1.1     joerg     return -1;
    469   1.1     joerg   if (n1->ehframe_base > n2->ehframe_base)
    470   1.1     joerg     return 1;
    471   1.1     joerg   return 0;
    472   1.1     joerg }
    473   1.1     joerg 
    474   1.1     joerg static int dsoTableCmpKey(void *context, const void *n_, const void *ptr_) {
    475   1.2     joerg   const LocalAddressSpace::Range *n = (const LocalAddressSpace::Range *)n_;
    476   1.2     joerg   const LocalAddressSpace::pint_t *ptr = (const LocalAddressSpace::pint_t *)ptr_;
    477   1.1     joerg   if (n->ehframe_base < *ptr)
    478   1.1     joerg     return -1;
    479   1.1     joerg   if (n->ehframe_base > *ptr)
    480   1.1     joerg     return 1;
    481   1.1     joerg   return 0;
    482   1.1     joerg }
    483   1.1     joerg 
    484   1.1     joerg } // namespace _Unwind
    485   1.1     joerg 
    486   1.1     joerg #endif // __ADDRESSSPACE_HPP__
    487