1 //===-- CPPLanguageRuntime.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/Target/CPPLanguageRuntime.h" 11 12 #include <string.h> 13 14 #include "lldb/Core/PluginManager.h" 15 #include "lldb/Core/UniqueCStringMap.h" 16 #include "lldb/Target/ExecutionContext.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 class CPPRuntimeEquivalents 22 { 23 public: 24 CPPRuntimeEquivalents () 25 { 26 27 m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>")); 28 29 // these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container 30 m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>")); 31 32 m_impl.Sort(); 33 } 34 35 void 36 Add (ConstString& type_name, 37 ConstString& type_equivalent) 38 { 39 m_impl.Insert(type_name.AsCString(), type_equivalent); 40 } 41 42 uint32_t 43 FindExactMatches (ConstString& type_name, 44 std::vector<ConstString>& equivalents) 45 { 46 47 uint32_t count = 0; 48 49 for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString()); 50 match != NULL; 51 match = m_impl.FindNextValueForName(match)) 52 { 53 equivalents.push_back(match->value); 54 count++; 55 } 56 57 return count; 58 } 59 60 // partial matches can occur when a name with equivalents is a template argument. 61 // e.g. we may have "class Foo" be a match for "struct Bar". if we have a typename 62 // such as "class Templatized<class Foo, Anything>" we want this to be replaced with 63 // "class Templatized<struct Bar, Anything>". Since partial matching is time consuming 64 // once we get a partial match, we add it to the exact matches list for faster retrieval 65 uint32_t 66 FindPartialMatches (ConstString& type_name, 67 std::vector<ConstString>& equivalents) 68 { 69 70 uint32_t count = 0; 71 72 const char* type_name_cstr = type_name.AsCString(); 73 74 size_t items_count = m_impl.GetSize(); 75 76 for (size_t item = 0; item < items_count; item++) 77 { 78 const char* key_cstr = m_impl.GetCStringAtIndex(item); 79 if ( strstr(type_name_cstr,key_cstr) ) 80 { 81 count += AppendReplacements(type_name_cstr, 82 key_cstr, 83 equivalents); 84 } 85 } 86 87 return count; 88 89 } 90 91 private: 92 93 std::string& replace (std::string& target, 94 std::string& pattern, 95 std::string& with) 96 { 97 size_t pos; 98 size_t pattern_len = pattern.size(); 99 100 while ( (pos = target.find(pattern)) != std::string::npos ) 101 target.replace(pos, pattern_len, with); 102 103 return target; 104 } 105 106 uint32_t 107 AppendReplacements (const char* original, 108 const char *matching_key, 109 std::vector<ConstString>& equivalents) 110 { 111 112 std::string matching_key_str(matching_key); 113 ConstString original_const(original); 114 115 uint32_t count = 0; 116 117 for (ImplData match = m_impl.FindFirstValueForName(matching_key); 118 match != NULL; 119 match = m_impl.FindNextValueForName(match)) 120 { 121 std::string target(original); 122 std::string equiv_class(match->value.AsCString()); 123 124 replace (target, matching_key_str, equiv_class); 125 126 ConstString target_const(target.c_str()); 127 128 // you will most probably want to leave this off since it might make this map grow indefinitely 129 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW 130 Add(original_const, target_const); 131 #endif 132 equivalents.push_back(target_const); 133 134 count++; 135 } 136 137 return count; 138 } 139 140 typedef UniqueCStringMap<ConstString> Impl; 141 typedef const Impl::Entry* ImplData; 142 Impl m_impl; 143 }; 144 145 static CPPRuntimeEquivalents& 146 GetEquivalentsMap () 147 { 148 static CPPRuntimeEquivalents g_equivalents_map; 149 return g_equivalents_map; 150 } 151 152 //---------------------------------------------------------------------- 153 // Destructor 154 //---------------------------------------------------------------------- 155 CPPLanguageRuntime::~CPPLanguageRuntime() 156 { 157 } 158 159 CPPLanguageRuntime::CPPLanguageRuntime (Process *process) : 160 LanguageRuntime (process) 161 { 162 163 } 164 165 bool 166 CPPLanguageRuntime::GetObjectDescription (Stream &str, ValueObject &object) 167 { 168 // C++ has no generic way to do this. 169 return false; 170 } 171 172 bool 173 CPPLanguageRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) 174 { 175 // C++ has no generic way to do this. 176 return false; 177 } 178 179 bool 180 CPPLanguageRuntime::IsCPPMangledName (const char *name) 181 { 182 // FIXME, we should really run through all the known C++ Language plugins and ask each one if 183 // this is a C++ mangled name, but we can put that off till there is actually more than one 184 // we care about. 185 186 if (name && name[0] == '_' && name[1] == 'Z') 187 return true; 188 else 189 return false; 190 } 191 192 bool 193 CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end) 194 { 195 if (base_name_end == NULL) 196 base_name_end = name + strlen (name); 197 198 const char *last_colon = strrchr (name, ':'); 199 200 if (last_colon == NULL) 201 { 202 base_name_start = name; 203 return true; 204 } 205 206 // Can't have a C++ name that begins with a single ':', nor contains an internal single ':' 207 if (last_colon == name) 208 return false; 209 else if (last_colon[-1] != ':') 210 return false; 211 else 212 { 213 // FIXME: should check if there is 214 base_name_start = last_colon + 1; 215 return true; 216 } 217 } 218 219 uint32_t 220 CPPLanguageRuntime::FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents) 221 { 222 uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents); 223 224 bool might_have_partials= 225 ( count == 0 ) // if we have a full name match just use it 226 && (strchr(type_name.AsCString(), '<') != NULL // we should only have partial matches when templates are involved, check that we have 227 && strchr(type_name.AsCString(), '>') != NULL); // angle brackets in the type_name before trying to scan for partial matches 228 229 if ( might_have_partials ) 230 count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents); 231 232 return count; 233 } 234 235 void 236 CPPLanguageRuntime::MethodName::Clear() 237 { 238 m_full.Clear(); 239 m_basename = llvm::StringRef(); 240 m_context = llvm::StringRef(); 241 m_arguments = llvm::StringRef(); 242 m_qualifiers = llvm::StringRef(); 243 m_type = eTypeInvalid; 244 m_parsed = false; 245 m_parse_error = false; 246 } 247 248 bool 249 ReverseFindMatchingChars (const llvm::StringRef &s, 250 const llvm::StringRef &left_right_chars, 251 size_t &left_pos, 252 size_t &right_pos, 253 size_t pos = llvm::StringRef::npos) 254 { 255 assert (left_right_chars.size() == 2); 256 left_pos = llvm::StringRef::npos; 257 const char left_char = left_right_chars[0]; 258 const char right_char = left_right_chars[1]; 259 pos = s.find_last_of(left_right_chars, pos); 260 if (pos == llvm::StringRef::npos || s[pos] == left_char) 261 return false; 262 right_pos = pos; 263 uint32_t depth = 1; 264 while (pos > 0 && depth > 0) 265 { 266 pos = s.find_last_of(left_right_chars, pos); 267 if (pos == llvm::StringRef::npos) 268 return false; 269 if (s[pos] == left_char) 270 { 271 if (--depth == 0) 272 { 273 left_pos = pos; 274 return left_pos < right_pos; 275 } 276 } 277 else if (s[pos] == right_char) 278 { 279 ++depth; 280 } 281 } 282 return false; 283 } 284 285 void 286 CPPLanguageRuntime::MethodName::Parse() 287 { 288 if (!m_parsed && m_full) 289 { 290 // ConstString mangled; 291 // m_full.GetMangledCounterpart(mangled); 292 // printf ("\n parsing = '%s'\n", m_full.GetCString()); 293 // if (mangled) 294 // printf (" mangled = '%s'\n", mangled.GetCString()); 295 m_parse_error = false; 296 m_parsed = true; 297 llvm::StringRef full (m_full.GetCString()); 298 299 size_t arg_start, arg_end; 300 llvm::StringRef parens("()", 2); 301 if (ReverseFindMatchingChars (full, parens, arg_start, arg_end)) 302 { 303 m_arguments = full.substr(arg_start, arg_end - arg_start + 1); 304 if (arg_end + 1 < full.size()) 305 m_qualifiers = full.substr(arg_end + 1); 306 if (arg_start > 0) 307 { 308 size_t basename_end = arg_start; 309 size_t context_end = llvm::StringRef::npos; 310 if (basename_end > 0 && full[basename_end-1] == '>') 311 { 312 // TODO: handle template junk... 313 // Templated function 314 size_t template_start, template_end; 315 llvm::StringRef lt_gt("<>", 2); 316 if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end)) 317 context_end = full.rfind(':', template_start); 318 } 319 if (context_end == llvm::StringRef::npos) 320 context_end = full.rfind(':', basename_end); 321 322 if (context_end == llvm::StringRef::npos) 323 m_basename = full.substr(0, basename_end); 324 else 325 { 326 m_context = full.substr(0, context_end - 1); 327 const size_t basename_begin = context_end + 1; 328 m_basename = full.substr(basename_begin, basename_end - basename_begin); 329 } 330 m_type = eTypeUnknownMethod; 331 } 332 else 333 { 334 m_parse_error = true; 335 return; 336 } 337 338 // if (!m_context.empty()) 339 // printf (" context = '%s'\n", m_context.str().c_str()); 340 // if (m_basename) 341 // printf (" basename = '%s'\n", m_basename.GetCString()); 342 // if (!m_arguments.empty()) 343 // printf (" arguments = '%s'\n", m_arguments.str().c_str()); 344 // if (!m_qualifiers.empty()) 345 // printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str()); 346 } 347 else 348 { 349 m_parse_error = true; 350 // printf ("error: didn't find matching parens for arguments\n"); 351 } 352 } 353 } 354 355 llvm::StringRef 356 CPPLanguageRuntime::MethodName::GetBasename () 357 { 358 if (!m_parsed) 359 Parse(); 360 return m_basename; 361 } 362 363 llvm::StringRef 364 CPPLanguageRuntime::MethodName::GetContext () 365 { 366 if (!m_parsed) 367 Parse(); 368 return m_context; 369 } 370 371 llvm::StringRef 372 CPPLanguageRuntime::MethodName::GetArguments () 373 { 374 if (!m_parsed) 375 Parse(); 376 return m_arguments; 377 } 378 379 llvm::StringRef 380 CPPLanguageRuntime::MethodName::GetQualifiers () 381 { 382 if (!m_parsed) 383 Parse(); 384 return m_qualifiers; 385 } 386 387