Home | History | Annotate | Download | only in source
      1 //===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  Created by Greg Clayton on 6/29/07.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "DNBBreakpoint.h"
     15 #include "MachProcess.h"
     16 #include <assert.h>
     17 #include <algorithm>
     18 #include <inttypes.h>
     19 #include "DNBLog.h"
     20 
     21 
     22 #pragma mark -- DNBBreakpoint
     23 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, bool hardware) :
     24     m_retain_count (1),
     25     m_byte_size (byte_size),
     26     m_opcode(),
     27     m_addr(addr),
     28     m_enabled(0),
     29     m_hw_preferred(hardware),
     30     m_is_watchpoint(0),
     31     m_watch_read(0),
     32     m_watch_write(0),
     33     m_hw_index(INVALID_NUB_HW_INDEX)
     34 {
     35 }
     36 
     37 DNBBreakpoint::~DNBBreakpoint()
     38 {
     39 }
     40 
     41 void
     42 DNBBreakpoint::Dump() const
     43 {
     44     if (IsBreakpoint())
     45     {
     46         DNBLog ("DNBBreakpoint addr = 0x%llx  state = %s  type = %s breakpoint  hw_index = %i",
     47                 (uint64_t)m_addr,
     48                 m_enabled ? "enabled " : "disabled",
     49                 IsHardware() ? "hardware" : "software",
     50                 GetHardwareIndex());
     51     }
     52     else
     53     {
     54         DNBLog ("DNBBreakpoint addr = 0x%llx  size = %llu  state = %s  type = %s watchpoint (%s%s)  hw_index = %i",
     55                 (uint64_t)m_addr,
     56                 (uint64_t)m_byte_size,
     57                 m_enabled ? "enabled " : "disabled",
     58                 IsHardware() ? "hardware" : "software",
     59                 m_watch_read ? "r" : "",
     60                 m_watch_write ? "w" : "",
     61                 GetHardwareIndex());
     62     }
     63 }
     64 
     65 #pragma mark -- DNBBreakpointList
     66 
     67 DNBBreakpointList::DNBBreakpointList()
     68 {
     69 }
     70 
     71 DNBBreakpointList::~DNBBreakpointList()
     72 {
     73 }
     74 
     75 
     76 DNBBreakpoint *
     77 DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length, bool hardware)
     78 {
     79     m_breakpoints.insert(std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
     80     iterator pos = m_breakpoints.find (addr);
     81     return &pos->second;
     82 }
     83 
     84 bool
     85 DNBBreakpointList::Remove (nub_addr_t addr)
     86 {
     87     iterator pos = m_breakpoints.find(addr);
     88     if (pos != m_breakpoints.end())
     89     {
     90         m_breakpoints.erase(pos);
     91         return true;
     92     }
     93     return false;
     94 }
     95 
     96 DNBBreakpoint *
     97 DNBBreakpointList::FindByAddress (nub_addr_t addr)
     98 {
     99     iterator pos = m_breakpoints.find(addr);
    100     if (pos != m_breakpoints.end())
    101         return &pos->second;
    102 
    103     return NULL;
    104 }
    105 
    106 const DNBBreakpoint *
    107 DNBBreakpointList::FindByAddress (nub_addr_t addr) const
    108 {
    109     const_iterator pos = m_breakpoints.find(addr);
    110     if (pos != m_breakpoints.end())
    111         return &pos->second;
    112 
    113     return NULL;
    114 }
    115 
    116 // Finds the next breakpoint at an address greater than or equal to "addr"
    117 size_t
    118 DNBBreakpointList::FindBreakpointsThatOverlapRange (nub_addr_t addr,
    119                                                     nub_addr_t size,
    120                                                     std::vector<DNBBreakpoint *> &bps)
    121 {
    122     bps.clear();
    123     iterator end = m_breakpoints.end();
    124     // Find the first breakpoint with an address >= to "addr"
    125     iterator pos = m_breakpoints.lower_bound(addr);
    126     if (pos != end)
    127     {
    128         if (pos != m_breakpoints.begin())
    129         {
    130             // Watch out for a breakpoint at an address less than "addr" that might still overlap
    131             iterator prev_pos = pos;
    132             --prev_pos;
    133             if (prev_pos->second.IntersectsRange (addr, size, NULL, NULL, NULL))
    134                 bps.push_back (&pos->second);
    135 
    136         }
    137 
    138         while (pos != end)
    139         {
    140             // When we hit a breakpoint whose start address is greater than "addr + size" we are done.
    141             // Do the math in a way that doesn't risk unsigned overflow with bad input.
    142             if ((pos->second.Address() - addr) >= size)
    143                 break;
    144 
    145             // Check if this breakpoint overlaps, and if it does, add it to the list
    146             if (pos->second.IntersectsRange (addr, size, NULL, NULL, NULL))
    147             {
    148                 bps.push_back (&pos->second);
    149                 ++pos;
    150             }
    151         }
    152     }
    153     return bps.size();
    154 }
    155 
    156 void
    157 DNBBreakpointList::Dump() const
    158 {
    159     const_iterator pos;
    160     const_iterator end = m_breakpoints.end();
    161     for (pos = m_breakpoints.begin(); pos != end; ++pos)
    162         pos->second.Dump();
    163 }
    164 
    165 void
    166 DNBBreakpointList::DisableAll ()
    167 {
    168     iterator pos, end = m_breakpoints.end();
    169     for (pos = m_breakpoints.begin(); pos != end; ++pos)
    170         pos->second.SetEnabled(false);
    171 }
    172 
    173 
    174 void
    175 DNBBreakpointList::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, void *p) const
    176 {
    177     uint8_t *buf = (uint8_t *)p;
    178     const_iterator end = m_breakpoints.end();
    179     const_iterator pos = m_breakpoints.lower_bound(addr);
    180     while (pos != end && (pos->first < (addr + size)))
    181     {
    182         nub_addr_t intersect_addr;
    183         nub_size_t intersect_size;
    184         nub_size_t opcode_offset;
    185         const DNBBreakpoint &bp = pos->second;
    186         if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset))
    187         {
    188             assert(addr <= intersect_addr && intersect_addr < addr + size);
    189             assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
    190             assert(opcode_offset + intersect_size <= bp.ByteSize());
    191             nub_size_t buf_offset = intersect_addr - addr;
    192             ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset, intersect_size);
    193         }
    194         ++pos;
    195     }
    196 }
    197 
    198 void
    199 DNBBreakpointList::DisableAllBreakpoints(MachProcess *process)
    200 {
    201     iterator pos, end = m_breakpoints.end();
    202     for (pos = m_breakpoints.begin(); pos != end; ++pos)
    203         process->DisableBreakpoint(pos->second.Address(), false);
    204 }
    205 
    206 void
    207 DNBBreakpointList::DisableAllWatchpoints(MachProcess *process)
    208 {
    209     iterator pos, end = m_breakpoints.end();
    210     for (pos = m_breakpoints.begin(); pos != end; ++pos)
    211         process->DisableWatchpoint(pos->second.Address(), false);
    212 }
    213 
    214 void
    215 DNBBreakpointList::RemoveDisabled()
    216 {
    217     iterator pos = m_breakpoints.begin();
    218     while (pos != m_breakpoints.end())
    219     {
    220         if (!pos->second.IsEnabled())
    221             pos = m_breakpoints.erase(pos);
    222         else
    223             ++pos;
    224     }
    225 }
    226