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 #include "lldb/Target/Process.h" 12 #include "lldb/Target/RegisterContext.h" 13 #include "lldb/Target/Thread.h" 14 #include "lldb/Core/ConstString.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 bool 20 UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const 21 { 22 if (m_type != rhs.m_type) 23 return false; 24 if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset) 25 return m_location.offset == rhs.m_location.offset; 26 if (m_type == inOtherRegister) 27 return m_location.reg_num == rhs.m_location.reg_num; 28 if (m_type == atDWARFExpression || m_type == isDWARFExpression) 29 if (m_location.expr.length == rhs.m_location.expr.length) 30 return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length); 31 return false; 32 } 33 34 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 35 // memory for the lifespan of this UnwindPlan object. 36 void 37 UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len) 38 { 39 m_type = atDWARFExpression; 40 m_location.expr.opcodes = opcodes; 41 m_location.expr.length = len; 42 } 43 44 // This function doesn't copy the dwarf expression bytes; they must remain in allocated 45 // memory for the lifespan of this UnwindPlan object. 46 void 47 UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len) 48 { 49 m_type = isDWARFExpression; 50 m_location.expr.opcodes = opcodes; 51 m_location.expr.length = len; 52 } 53 54 void 55 UnwindPlan::Row::RegisterLocation::SetUnspecified () 56 { 57 m_type = unspecified; 58 } 59 60 void 61 UnwindPlan::Row::RegisterLocation::SetUndefined () 62 { 63 m_type = isUndefined; 64 } 65 66 void 67 UnwindPlan::Row::RegisterLocation::SetSame () 68 { 69 m_type = isSame; 70 } 71 72 73 void 74 UnwindPlan::Row::RegisterLocation::SetAtCFAPlusOffset (int32_t offset) 75 { 76 m_type = atCFAPlusOffset; 77 m_location.offset = offset; 78 } 79 80 void 81 UnwindPlan::Row::RegisterLocation::SetIsCFAPlusOffset (int32_t offset) 82 { 83 m_type = isCFAPlusOffset; 84 m_location.offset = offset; 85 } 86 87 void 88 UnwindPlan::Row::RegisterLocation::SetInRegister (uint32_t reg_num) 89 { 90 m_type = inOtherRegister; 91 m_location.reg_num = reg_num; 92 } 93 94 void 95 UnwindPlan::Row::RegisterLocation::Dump (Stream &s) const 96 { 97 switch (m_type) 98 { 99 case unspecified: 100 s.PutCString ("unspecified"); 101 break; 102 case isUndefined: 103 s.PutCString ("isUndefined"); 104 break; 105 case isSame: 106 s.PutCString ("isSame"); 107 break; 108 case atCFAPlusOffset: 109 s.Printf ("atCFAPlusOffset %d", m_location.offset); 110 break; 111 case isCFAPlusOffset: 112 s.Printf ("isCFAPlusOffset %d", m_location.offset); 113 break; 114 case inOtherRegister: 115 s.Printf ("inOtherRegister %d", m_location.reg_num); 116 break; 117 case atDWARFExpression: 118 s.PutCString ("atDWARFExpression"); 119 break; 120 case isDWARFExpression: 121 s.PutCString ("isDWARFExpression"); 122 break; 123 } 124 } 125 126 void 127 UnwindPlan::Row::Clear () 128 { 129 m_offset = 0; 130 m_cfa_reg_num = 0; 131 m_cfa_offset = 0; 132 m_register_locations.clear(); 133 } 134 135 void 136 UnwindPlan::Row::Dump (Stream& s, int register_kind, Thread* thread) const 137 { 138 RegisterContext *reg_ctx = NULL; 139 const RegisterInfo *rinfo = NULL; 140 int translated_regnum; 141 if (thread && thread->GetRegisterContext()) 142 reg_ctx = thread->GetRegisterContext().get(); 143 144 s.Printf ("offset %ld, CFA reg ", (long) GetOffset()); 145 if (reg_ctx 146 && (translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, GetCFARegister())) != -1 147 && (rinfo = reg_ctx->GetRegisterInfoAtIndex (translated_regnum)) != NULL 148 && rinfo->name != NULL 149 && rinfo->name[0] != '\0') 150 { 151 s.Printf ("%s, ", rinfo->name); 152 } 153 else 154 { 155 s.Printf ("%d, ", (int)(int) GetCFARegister()); 156 } 157 s.Printf ("CFA offset %d", (int) GetCFAOffset ()); 158 for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx) 159 { 160 s.PutCString (" ["); 161 bool printed_name = false; 162 if (reg_ctx) 163 { 164 translated_regnum = reg_ctx->ConvertRegisterKindToRegisterNumber (register_kind, idx->first); 165 rinfo = reg_ctx->GetRegisterInfoAtIndex (translated_regnum); 166 if (rinfo && rinfo->name) 167 { 168 s.Printf ("%s ", rinfo->name); 169 printed_name = true; 170 } 171 } 172 if (!printed_name) 173 { 174 s.Printf ("reg %d ", idx->first); 175 } 176 idx->second.Dump(s); 177 s.PutCString ("]"); 178 } 179 s.EOL(); 180 } 181 182 UnwindPlan::Row::Row() : 183 m_offset(0), 184 m_cfa_reg_num(0), 185 m_cfa_offset(0), 186 m_register_locations() 187 { 188 } 189 190 bool 191 UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const 192 { 193 collection::const_iterator pos = m_register_locations.find(reg_num); 194 if (pos != m_register_locations.end()) 195 { 196 register_location = pos->second; 197 return true; 198 } 199 return false; 200 } 201 202 void 203 UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location) 204 { 205 m_register_locations[reg_num] = register_location; 206 } 207 208 209 void 210 UnwindPlan::AppendRow (const UnwindPlan::Row &row) 211 { 212 if (m_row_list.empty() || m_row_list.back().GetOffset() != row.GetOffset()) 213 m_row_list.push_back(row); 214 else 215 m_row_list.back() = row; 216 } 217 218 const UnwindPlan::Row * 219 UnwindPlan::GetRowForFunctionOffset (int offset) const 220 { 221 const UnwindPlan::Row *row_ptr = NULL; 222 if (!m_row_list.empty()) 223 { 224 if (offset == -1) 225 row_ptr = &m_row_list.back(); 226 else 227 { 228 collection::const_iterator pos, end = m_row_list.end(); 229 for (pos = m_row_list.begin(); pos != end; ++pos) 230 { 231 if (pos->GetOffset() <= offset) 232 row_ptr = &*pos; 233 else 234 break; 235 } 236 } 237 } 238 return row_ptr; 239 } 240 241 bool 242 UnwindPlan::IsValidRowIndex (uint32_t idx) const 243 { 244 return idx < m_row_list.size(); 245 } 246 247 const UnwindPlan::Row& 248 UnwindPlan::GetRowAtIndex (uint32_t idx) const 249 { 250 // You must call IsValidRowIndex(idx) first before calling this!!! 251 assert (idx < m_row_list.size()); 252 return m_row_list[idx]; 253 } 254 255 int 256 UnwindPlan::GetRowCount () const 257 { 258 return m_row_list.size (); 259 } 260 261 void 262 UnwindPlan::SetRegisterKind (uint32_t rk) 263 { 264 m_register_kind = rk; 265 } 266 267 uint32_t 268 UnwindPlan::GetRegisterKind (void) const 269 { 270 return m_register_kind; 271 } 272 273 void 274 UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) 275 { 276 if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0) 277 m_plan_valid_address_range = range; 278 } 279 280 bool 281 UnwindPlan::PlanValidAtAddress (Address addr) 282 { 283 if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) 284 return true; 285 286 if (!addr.IsValid()) 287 return true; 288 289 if (m_plan_valid_address_range.ContainsFileAddress (addr)) 290 return true; 291 292 return false; 293 } 294 295 void 296 UnwindPlan::Dump (Stream& s, Thread *thread) const 297 { 298 if (!m_source_name.IsEmpty()) 299 { 300 s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString()); 301 } 302 if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) 303 { 304 s.PutCString ("Address range of this UnwindPlan: "); 305 m_plan_valid_address_range.Dump (&s, &thread->GetProcess().GetTarget(), Address::DumpStyleSectionNameOffset); 306 s.EOL(); 307 } 308 else 309 { 310 s.PutCString ("No valid address range recorded for this UnwindPlan.\n"); 311 } 312 s.Printf ("UnwindPlan register kind %d", m_register_kind); 313 switch (m_register_kind) 314 { 315 case eRegisterKindGCC: s.PutCString (" [eRegisterKindGCC]"); break; 316 case eRegisterKindDWARF: s.PutCString (" [eRegisterKindDWARF]"); break; 317 case eRegisterKindGeneric: s.PutCString (" [eRegisterKindGeneric]"); break; 318 case eRegisterKindGDB: s.PutCString (" [eRegisterKindGDB]"); break; 319 case eRegisterKindLLDB: s.PutCString (" [eRegisterKindLLDB]"); break; 320 default: break; 321 } 322 s.EOL(); 323 for (int i = 0; IsValidRowIndex (i); i++) 324 { 325 s.Printf ("UnwindPlan row at index %d: ", i); 326 m_row_list[i].Dump(s, m_register_kind, thread); 327 } 328 } 329 330 void 331 UnwindPlan::SetSourceName (const char *source) 332 { 333 m_source_name = ConstString (source); 334 } 335 336 ConstString 337 UnwindPlan::GetSourceName () const 338 { 339 return m_source_name; 340 } 341