Home | History | Annotate | Download | only in Symbol
      1 //===-- UnwindPlan.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 #include "lldb/Symbol/UnwindPlan.h"
     11 
     12 #include "lldb/Core/ConstString.h"
     13 #include "lldb/Target/Process.h"
     14 #include "lldb/Target/RegisterContext.h"
     15 #include "lldb/Target/Thread.h"
     16 
     17 using namespace lldb;
     18 using namespace lldb_private;
     19 
     20 bool
     21 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
     22 {
     23     if (m_type == rhs.m_type)
     24     {
     25         switch (m_type)
     26         {
     27             case unspecified:
     28             case undefined:
     29             case same:
     30                 return true;
     31 
     32             case atCFAPlusOffset:
     33             case isCFAPlusOffset:
     34                 return m_location.offset == rhs.m_location.offset;
     35 
     36             case inOtherRegister:
     37                 return m_location.reg_num == rhs.m_location.reg_num;
     38 
     39             case atDWARFExpression:
     40             case isDWARFExpression:
     41                 if (m_location.expr.length == rhs.m_location.expr.length)
     42                     return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
     43                 break;
     44         }
     45     }
     46     return false;
     47 }
     48 
     49 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
     50 // memory for the lifespan of this UnwindPlan object.
     51 void
     52 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
     53 {
     54     m_type = atDWARFExpression;
     55     m_location.expr.opcodes = opcodes;
     56     m_location.expr.length = len;
     57 }
     58 
     59 // This function doesn't copy the dwarf expression bytes; they must remain in allocated
     60 // memory for the lifespan of this UnwindPlan object.
     61 void
     62 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
     63 {
     64     m_type = isDWARFExpression;
     65     m_location.expr.opcodes = opcodes;
     66     m_location.expr.length = len;
     67 }
     68 
     69 void
     70 UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
     71 {
     72     switch (m_type)
     73     {
     74         case unspecified:
     75             if (verbose)
     76                 s.PutCString ("=<unspec>");
     77             else
     78                 s.PutCString ("=!");
     79             break;
     80         case undefined:
     81             if (verbose)
     82                 s.PutCString ("=<undef>");
     83             else
     84                 s.PutCString ("=?");
     85             break;
     86         case same:
     87             s.PutCString ("= <same>");
     88             break;
     89 
     90         case atCFAPlusOffset:
     91         case isCFAPlusOffset:
     92             {
     93                 s.PutChar('=');
     94                 if (m_type == atCFAPlusOffset)
     95                     s.PutChar('[');
     96                 if (verbose)
     97                     s.Printf ("CFA%+d", m_location.offset);
     98 
     99                 if (unwind_plan && row)
    100                 {
    101                     const uint32_t cfa_reg = row->GetCFARegister();
    102                     const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
    103                     const int32_t offset = row->GetCFAOffset() + m_location.offset;
    104                     if (verbose)
    105                     {
    106                         if (cfa_reg_info)
    107                             s.Printf (" (%s%+d)",  cfa_reg_info->name, offset);
    108                         else
    109                             s.Printf (" (reg(%u)%+d)",  cfa_reg, offset);
    110                     }
    111                     else
    112                     {
    113                         if (cfa_reg_info)
    114                             s.Printf ("%s",  cfa_reg_info->name);
    115                         else
    116                             s.Printf ("reg(%u)",  cfa_reg);
    117                         if (offset != 0)
    118                             s.Printf ("%+d", offset);
    119                     }
    120                 }
    121                 if (m_type == atCFAPlusOffset)
    122                     s.PutChar(']');
    123             }
    124             break;
    125 
    126         case inOtherRegister:
    127             {
    128                 const RegisterInfo *other_reg_info = NULL;
    129                 if (unwind_plan)
    130                     other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
    131                 if (other_reg_info)
    132                     s.Printf ("=%s", other_reg_info->name);
    133                 else
    134                     s.Printf ("=reg(%u)", m_location.reg_num);
    135             }
    136             break;
    137 
    138         case atDWARFExpression:
    139         case isDWARFExpression:
    140             {
    141                 s.PutChar('=');
    142                 if (m_type == atDWARFExpression)
    143                     s.PutCString("[dwarf-expr]");
    144                 else
    145                     s.PutCString("dwarf-expr");
    146             }
    147             break;
    148 
    149     }
    150 }
    151 
    152 void
    153 UnwindPlan::Row::Clear ()
    154 {
    155     m_offset = 0;
    156     m_cfa_reg_num = LLDB_INVALID_REGNUM;
    157     m_cfa_offset = 0;
    158     m_register_locations.clear();
    159 }
    160 
    161 void
    162 UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
    163 {
    164     const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
    165 
    166     if (base_addr != LLDB_INVALID_ADDRESS)
    167         s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
    168     else
    169         s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
    170 
    171     if (reg_info)
    172         s.Printf ("%s", reg_info->name);
    173     else
    174         s.Printf ("reg(%u)", GetCFARegister());
    175     s.Printf ("%+3d => ", GetCFAOffset ());
    176     for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
    177     {
    178         reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
    179         if (reg_info)
    180             s.Printf ("%s", reg_info->name);
    181         else
    182             s.Printf ("reg(%u)", idx->first);
    183         const bool verbose = false;
    184         idx->second.Dump(s, unwind_plan, this, thread, verbose);
    185         s.PutChar (' ');
    186     }
    187     s.EOL();
    188 }
    189 
    190 UnwindPlan::Row::Row() :
    191     m_offset(0),
    192     m_cfa_reg_num(LLDB_INVALID_REGNUM),
    193     m_cfa_offset(0),
    194     m_register_locations()
    195 {
    196 }
    197 
    198 bool
    199 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
    200 {
    201     collection::const_iterator pos = m_register_locations.find(reg_num);
    202     if (pos != m_register_locations.end())
    203     {
    204         register_location = pos->second;
    205         return true;
    206     }
    207     return false;
    208 }
    209 
    210 void
    211 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
    212 {
    213     m_register_locations[reg_num] = register_location;
    214 }
    215 
    216 bool
    217 UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
    218 {
    219     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
    220         return false;
    221     RegisterLocation reg_loc;
    222     reg_loc.SetAtCFAPlusOffset(offset);
    223     m_register_locations[reg_num] = reg_loc;
    224     return true;
    225 }
    226 
    227 bool
    228 UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
    229 {
    230     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
    231         return false;
    232     RegisterLocation reg_loc;
    233     reg_loc.SetIsCFAPlusOffset(offset);
    234     m_register_locations[reg_num] = reg_loc;
    235     return true;
    236 }
    237 
    238 bool
    239 UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
    240 {
    241     collection::iterator pos = m_register_locations.find(reg_num);
    242     collection::iterator end = m_register_locations.end();
    243 
    244     if (pos != end)
    245     {
    246         if (!can_replace)
    247             return false;
    248         if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
    249             return false;
    250     }
    251     RegisterLocation reg_loc;
    252     reg_loc.SetUndefined();
    253     m_register_locations[reg_num] = reg_loc;
    254     return true;
    255 }
    256 
    257 bool
    258 UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
    259 {
    260     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
    261         return false;
    262     RegisterLocation reg_loc;
    263     reg_loc.SetUnspecified();
    264     m_register_locations[reg_num] = reg_loc;
    265     return true;
    266 }
    267 
    268 bool
    269 UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
    270                                                 uint32_t other_reg_num,
    271                                                 bool can_replace)
    272 {
    273     if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
    274         return false;
    275     RegisterLocation reg_loc;
    276     reg_loc.SetInRegister(other_reg_num);
    277     m_register_locations[reg_num] = reg_loc;
    278     return true;
    279 }
    280 
    281 bool
    282 UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
    283 {
    284     if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
    285         return false;
    286     RegisterLocation reg_loc;
    287     reg_loc.SetSame();
    288     m_register_locations[reg_num] = reg_loc;
    289     return true;
    290 }
    291 
    292 void
    293 UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
    294 {
    295     m_cfa_reg_num = reg_num;
    296 }
    297 
    298 bool
    299 UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
    300 {
    301     if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
    302         return false;
    303     return m_register_locations == rhs.m_register_locations;
    304 }
    305 
    306 void
    307 UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
    308 {
    309     if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
    310         m_row_list.push_back(row_sp);
    311     else
    312         m_row_list.back() = row_sp;
    313 }
    314 
    315 UnwindPlan::RowSP
    316 UnwindPlan::GetRowForFunctionOffset (int offset) const
    317 {
    318     RowSP row;
    319     if (!m_row_list.empty())
    320     {
    321         if (offset == -1)
    322             row = m_row_list.back();
    323         else
    324         {
    325             collection::const_iterator pos, end = m_row_list.end();
    326             for (pos = m_row_list.begin(); pos != end; ++pos)
    327             {
    328                 if ((*pos)->GetOffset() <= offset)
    329                     row = *pos;
    330                 else
    331                     break;
    332             }
    333         }
    334     }
    335     return row;
    336 }
    337 
    338 bool
    339 UnwindPlan::IsValidRowIndex (uint32_t idx) const
    340 {
    341     return idx < m_row_list.size();
    342 }
    343 
    344 const UnwindPlan::RowSP
    345 UnwindPlan::GetRowAtIndex (uint32_t idx) const
    346 {
    347     // You must call IsValidRowIndex(idx) first before calling this!!!
    348     assert (idx < m_row_list.size());
    349     return m_row_list[idx];
    350 }
    351 
    352 const UnwindPlan::RowSP
    353 UnwindPlan::GetLastRow () const
    354 {
    355     // You must call GetRowCount() first to make sure there is at least one row
    356     assert (!m_row_list.empty());
    357     return m_row_list.back();
    358 }
    359 
    360 int
    361 UnwindPlan::GetRowCount () const
    362 {
    363     return m_row_list.size ();
    364 }
    365 
    366 void
    367 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
    368 {
    369    if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
    370        m_plan_valid_address_range = range;
    371 }
    372 
    373 bool
    374 UnwindPlan::PlanValidAtAddress (Address addr)
    375 {
    376     if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
    377         return true;
    378 
    379     if (!addr.IsValid())
    380         return true;
    381 
    382     if (m_plan_valid_address_range.ContainsFileAddress (addr))
    383         return true;
    384 
    385     return false;
    386 }
    387 
    388 void
    389 UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
    390 {
    391     if (!m_source_name.IsEmpty())
    392     {
    393         s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
    394     }
    395     if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
    396     {
    397         s.PutCString ("Address range of this UnwindPlan: ");
    398         TargetSP target_sp(thread->CalculateTarget());
    399         m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
    400         s.EOL();
    401     }
    402     collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
    403     for (pos = begin; pos != end; ++pos)
    404     {
    405         s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
    406         (*pos)->Dump(s, this, thread, base_addr);
    407     }
    408 }
    409 
    410 void
    411 UnwindPlan::SetSourceName (const char *source)
    412 {
    413     m_source_name = ConstString (source);
    414 }
    415 
    416 ConstString
    417 UnwindPlan::GetSourceName () const
    418 {
    419     return m_source_name;
    420 }
    421 
    422 const RegisterInfo *
    423 UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
    424 {
    425     if (thread)
    426     {
    427         RegisterContext *reg_ctx = thread->GetRegisterContext().get();
    428         if (reg_ctx)
    429         {
    430             uint32_t reg;
    431             if (m_register_kind == eRegisterKindLLDB)
    432                 reg = unwind_reg;
    433             else
    434                 reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
    435             if (reg != LLDB_INVALID_REGNUM)
    436                 return reg_ctx->GetRegisterInfoAtIndex (reg);
    437         }
    438     }
    439     return NULL;
    440 }
    441 
    442