| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2017 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | #include <assert.h> | 
 | 18 |  | 
 | 19 | #include <cctype> | 
 | 20 | #include <stack> | 
 | 21 | #include <string> | 
 | 22 | #include <vector> | 
 | 23 |  | 
 | 24 | #include "Demangler.h" | 
 | 25 |  | 
 | 26 | constexpr const char* Demangler::kTypes[]; | 
 | 27 | constexpr const char* Demangler::kDTypes[]; | 
 | 28 | constexpr const char* Demangler::kSTypes[]; | 
 | 29 |  | 
 | 30 | void Demangler::Save(const std::string& str, bool is_name) { | 
 | 31 |   saves_.push_back(str); | 
 | 32 |   last_save_name_ = is_name; | 
 | 33 | } | 
 | 34 |  | 
 | 35 | std::string Demangler::GetArgumentsString() { | 
 | 36 |   size_t num_args = cur_state_.args.size(); | 
 | 37 |   std::string arg_str; | 
 | 38 |   if (num_args > 0) { | 
 | 39 |     arg_str = cur_state_.args[0]; | 
 | 40 |     for (size_t i = 1; i < num_args; i++) { | 
 | 41 |       arg_str += ", " + cur_state_.args[i]; | 
 | 42 |     } | 
 | 43 |   } | 
 | 44 |   return arg_str; | 
 | 45 | } | 
 | 46 |  | 
 | 47 | const char* Demangler::AppendOperatorString(const char* name) { | 
 | 48 |   const char* oper = nullptr; | 
 | 49 |   switch (*name) { | 
 | 50 |   case 'a': | 
 | 51 |     name++; | 
 | 52 |     switch (*name) { | 
 | 53 |     case 'a': | 
 | 54 |       oper = "operator&&"; | 
 | 55 |       break; | 
 | 56 |     case 'd': | 
 | 57 |     case 'n': | 
 | 58 |       oper = "operator&"; | 
 | 59 |       break; | 
 | 60 |     case 'N': | 
 | 61 |       oper = "operator&="; | 
 | 62 |       break; | 
 | 63 |     case 'S': | 
 | 64 |       oper = "operator="; | 
 | 65 |       break; | 
 | 66 |     } | 
 | 67 |     break; | 
 | 68 |   case 'c': | 
 | 69 |     name++; | 
 | 70 |     switch (*name) { | 
 | 71 |     case 'l': | 
 | 72 |       oper = "operator()"; | 
 | 73 |       break; | 
 | 74 |     case 'm': | 
 | 75 |       oper = "operator,"; | 
 | 76 |       break; | 
 | 77 |     case 'o': | 
 | 78 |       oper = "operator~"; | 
 | 79 |       break; | 
 | 80 |     } | 
 | 81 |     break; | 
 | 82 |   case 'd': | 
 | 83 |     name++; | 
 | 84 |     switch (*name) { | 
 | 85 |     case 'a': | 
 | 86 |       oper = "operator delete[]"; | 
 | 87 |       break; | 
 | 88 |     case 'e': | 
 | 89 |       oper = "operator*"; | 
 | 90 |       break; | 
 | 91 |     case 'l': | 
 | 92 |       oper = "operator delete"; | 
 | 93 |       break; | 
 | 94 |     case 'v': | 
 | 95 |       oper = "operator/"; | 
 | 96 |       break; | 
 | 97 |     case 'V': | 
 | 98 |       oper = "operator/="; | 
 | 99 |       break; | 
 | 100 |     } | 
 | 101 |     break; | 
 | 102 |   case 'e': | 
 | 103 |     name++; | 
 | 104 |     switch (*name) { | 
 | 105 |     case 'o': | 
 | 106 |       oper = "operator^"; | 
 | 107 |       break; | 
 | 108 |     case 'O': | 
 | 109 |       oper = "operator^="; | 
 | 110 |       break; | 
 | 111 |     case 'q': | 
 | 112 |       oper = "operator=="; | 
 | 113 |       break; | 
 | 114 |     } | 
 | 115 |     break; | 
 | 116 |   case 'g': | 
 | 117 |     name++; | 
 | 118 |     switch (*name) { | 
 | 119 |     case 'e': | 
 | 120 |       oper = "operator>="; | 
 | 121 |       break; | 
 | 122 |     case 't': | 
 | 123 |       oper = "operator>"; | 
 | 124 |       break; | 
 | 125 |     } | 
 | 126 |     break; | 
 | 127 |   case 'i': | 
 | 128 |     name++; | 
 | 129 |     switch (*name) { | 
 | 130 |     case 'x': | 
 | 131 |       oper = "operator[]"; | 
 | 132 |       break; | 
 | 133 |     } | 
 | 134 |     break; | 
 | 135 |   case 'l': | 
 | 136 |     name++; | 
 | 137 |     switch (*name) { | 
 | 138 |     case 'e': | 
 | 139 |       oper = "operator<="; | 
 | 140 |       break; | 
 | 141 |     case 's': | 
 | 142 |       oper = "operator<<"; | 
 | 143 |       break; | 
 | 144 |     case 'S': | 
 | 145 |       oper = "operator<<="; | 
 | 146 |       break; | 
 | 147 |     case 't': | 
 | 148 |       oper = "operator<"; | 
 | 149 |       break; | 
 | 150 |     } | 
 | 151 |     break; | 
 | 152 |   case 'm': | 
 | 153 |     name++; | 
 | 154 |     switch (*name) { | 
 | 155 |     case 'i': | 
 | 156 |       oper = "operator-"; | 
 | 157 |       break; | 
 | 158 |     case 'I': | 
 | 159 |       oper = "operator-="; | 
 | 160 |       break; | 
 | 161 |     case 'l': | 
 | 162 |       oper = "operator*"; | 
 | 163 |       break; | 
 | 164 |     case 'L': | 
 | 165 |       oper = "operator*="; | 
 | 166 |       break; | 
 | 167 |     case 'm': | 
 | 168 |       oper = "operator--"; | 
 | 169 |       break; | 
 | 170 |     } | 
 | 171 |     break; | 
 | 172 |   case 'n': | 
 | 173 |     name++; | 
 | 174 |     switch (*name) { | 
 | 175 |     case 'a': | 
 | 176 |       oper = "operator new[]"; | 
 | 177 |       break; | 
 | 178 |     case 'e': | 
 | 179 |       oper = "operator!="; | 
 | 180 |       break; | 
 | 181 |     case 'g': | 
 | 182 |       oper = "operator-"; | 
 | 183 |       break; | 
 | 184 |     case 't': | 
 | 185 |       oper = "operator!"; | 
 | 186 |       break; | 
 | 187 |     case 'w': | 
 | 188 |       oper = "operator new"; | 
 | 189 |       break; | 
 | 190 |     } | 
 | 191 |     break; | 
 | 192 |   case 'o': | 
 | 193 |     name++; | 
 | 194 |     switch (*name) { | 
 | 195 |     case 'o': | 
 | 196 |       oper = "operator||"; | 
 | 197 |       break; | 
 | 198 |     case 'r': | 
 | 199 |       oper = "operator|"; | 
 | 200 |       break; | 
 | 201 |     case 'R': | 
 | 202 |       oper = "operator|="; | 
 | 203 |       break; | 
 | 204 |     } | 
 | 205 |     break; | 
 | 206 |   case 'p': | 
 | 207 |     name++; | 
 | 208 |     switch (*name) { | 
 | 209 |     case 'm': | 
 | 210 |       oper = "operator->*"; | 
 | 211 |       break; | 
 | 212 |     case 'l': | 
 | 213 |       oper = "operator+"; | 
 | 214 |       break; | 
 | 215 |     case 'L': | 
 | 216 |       oper = "operator+="; | 
 | 217 |       break; | 
 | 218 |     case 'p': | 
 | 219 |       oper = "operator++"; | 
 | 220 |       break; | 
 | 221 |     case 's': | 
 | 222 |       oper = "operator+"; | 
 | 223 |       break; | 
 | 224 |     case 't': | 
 | 225 |       oper = "operator->"; | 
 | 226 |       break; | 
 | 227 |     } | 
 | 228 |     break; | 
 | 229 |   case 'q': | 
 | 230 |     name++; | 
 | 231 |     switch (*name) { | 
 | 232 |     case 'u': | 
 | 233 |       oper = "operator?"; | 
 | 234 |       break; | 
 | 235 |     } | 
 | 236 |     break; | 
 | 237 |   case 'r': | 
 | 238 |     name++; | 
 | 239 |     switch (*name) { | 
 | 240 |     case 'm': | 
 | 241 |       oper = "operator%"; | 
 | 242 |       break; | 
 | 243 |     case 'M': | 
 | 244 |       oper = "operator%="; | 
 | 245 |       break; | 
 | 246 |     case 's': | 
 | 247 |       oper = "operator>>"; | 
 | 248 |       break; | 
 | 249 |     case 'S': | 
 | 250 |       oper = "operator>>="; | 
 | 251 |       break; | 
 | 252 |     } | 
 | 253 |     break; | 
 | 254 |   } | 
 | 255 |   if (oper == nullptr) { | 
 | 256 |     return nullptr; | 
 | 257 |   } | 
 | 258 |   AppendCurrent(oper); | 
 | 259 |   cur_state_.last_save = oper; | 
 | 260 |   return name + 1; | 
 | 261 | } | 
 | 262 |  | 
 | 263 | const char* Demangler::GetStringFromLength(const char* name, std::string* str) { | 
 | 264 |   assert(std::isdigit(*name)); | 
 | 265 |  | 
 | 266 |   size_t length = *name - '0'; | 
 | 267 |   name++; | 
 | 268 |   while (*name != '\0' && std::isdigit(*name)) { | 
 | 269 |     length = length * 10 + *name - '0'; | 
 | 270 |     name++; | 
 | 271 |   } | 
 | 272 |  | 
 | 273 |   std::string read_str; | 
 | 274 |   while (*name != '\0' && length != 0) { | 
 | 275 |     read_str += *name; | 
 | 276 |     name++; | 
 | 277 |     length--; | 
 | 278 |   } | 
 | 279 |   if (length != 0) { | 
 | 280 |     return nullptr; | 
 | 281 |   } | 
 | 282 |   // Special replacement of _GLOBAL__N_1 to (anonymous namespace). | 
 | 283 |   if (read_str == "_GLOBAL__N_1") { | 
 | 284 |     *str += "(anonymous namespace)"; | 
 | 285 |   } else { | 
 | 286 |     *str += read_str; | 
 | 287 |   } | 
 | 288 |   return name; | 
 | 289 | } | 
 | 290 |  | 
 | 291 | void Demangler::AppendCurrent(const std::string& str) { | 
 | 292 |   if (!cur_state_.str.empty()) { | 
 | 293 |     cur_state_.str += "::"; | 
 | 294 |   } | 
 | 295 |   cur_state_.str += str; | 
 | 296 | } | 
 | 297 |  | 
 | 298 | void Demangler::AppendCurrent(const char* str) { | 
 | 299 |   if (!cur_state_.str.empty()) { | 
 | 300 |     cur_state_.str += "::"; | 
 | 301 |   } | 
 | 302 |   cur_state_.str += str; | 
 | 303 | } | 
 | 304 |  | 
 | 305 | const char* Demangler::ParseS(const char* name) { | 
 | 306 |   if (std::islower(*name)) { | 
 | 307 |     const char* type = kSTypes[*name - 'a']; | 
 | 308 |     if (type == nullptr) { | 
 | 309 |       return nullptr; | 
 | 310 |     } | 
 | 311 |     AppendCurrent(type); | 
 | 312 |     return name + 1; | 
 | 313 |   } | 
 | 314 |  | 
 | 315 |   if (saves_.empty()) { | 
 | 316 |     return nullptr; | 
 | 317 |   } | 
 | 318 |  | 
 | 319 |   if (*name == '_') { | 
 | 320 |     last_save_name_ = false; | 
 | 321 |     AppendCurrent(saves_[0]); | 
 | 322 |     return name + 1; | 
 | 323 |   } | 
 | 324 |  | 
 | 325 |   bool isdigit = std::isdigit(*name); | 
 | 326 |   if (!isdigit && !std::isupper(*name)) { | 
 | 327 |     return nullptr; | 
 | 328 |   } | 
 | 329 |  | 
 | 330 |   size_t index; | 
 | 331 |   if (isdigit) { | 
 | 332 |     index = *name - '0' + 1; | 
 | 333 |   } else { | 
 | 334 |     index = *name - 'A' + 11; | 
 | 335 |   } | 
 | 336 |   name++; | 
 | 337 |   if (*name != '_') { | 
 | 338 |     return nullptr; | 
 | 339 |   } | 
 | 340 |  | 
 | 341 |   if (index >= saves_.size()) { | 
 | 342 |     return nullptr; | 
 | 343 |   } | 
 | 344 |  | 
 | 345 |   last_save_name_ = false; | 
 | 346 |   AppendCurrent(saves_[index]); | 
 | 347 |   return name + 1; | 
 | 348 | } | 
 | 349 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 350 | const char* Demangler::ParseT(const char* name) { | 
 | 351 |   if (template_saves_.empty()) { | 
 | 352 |     return nullptr; | 
 | 353 |   } | 
 | 354 |  | 
 | 355 |   if (*name == '_') { | 
 | 356 |     last_save_name_ = false; | 
 | 357 |     AppendCurrent(template_saves_[0]); | 
 | 358 |     return name + 1; | 
 | 359 |   } | 
 | 360 |  | 
 | 361 |   // Need to get the total number. | 
 | 362 |   char* end; | 
 | 363 |   unsigned long int index = strtoul(name, &end, 10) + 1; | 
 | 364 |   if (name == end || *end != '_') { | 
 | 365 |     return nullptr; | 
 | 366 |   } | 
 | 367 |  | 
 | 368 |   if (index >= template_saves_.size()) { | 
 | 369 |     return nullptr; | 
 | 370 |   } | 
 | 371 |  | 
 | 372 |   last_save_name_ = false; | 
 | 373 |   AppendCurrent(template_saves_[index]); | 
 | 374 |   return end + 1; | 
 | 375 | } | 
 | 376 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 377 | const char* Demangler::ParseFunctionName(const char* name) { | 
 | 378 |   if (*name == 'E') { | 
 | 379 |     if (parse_funcs_.empty()) { | 
 | 380 |       return nullptr; | 
 | 381 |     } | 
 | 382 |     parse_func_ = parse_funcs_.back(); | 
 | 383 |     parse_funcs_.pop_back(); | 
 | 384 |  | 
 | 385 |     // Remove the last saved part so that the full function name is not saved. | 
 | 386 |     // But only if the last save was not something like a substitution. | 
 | 387 |     if (!saves_.empty() && last_save_name_) { | 
 | 388 |       saves_.pop_back(); | 
 | 389 |     } | 
 | 390 |  | 
| Christopher Ferris | 5a72ea0 | 2017-11-01 16:22:09 -0700 | [diff] [blame] | 391 |     function_name_ += cur_state_.str; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 392 |     while (!cur_state_.suffixes.empty()) { | 
 | 393 |       function_suffix_ += cur_state_.suffixes.back(); | 
 | 394 |       cur_state_.suffixes.pop_back(); | 
 | 395 |     } | 
 | 396 |     cur_state_.Clear(); | 
 | 397 |  | 
 | 398 |     return name + 1; | 
 | 399 |   } | 
 | 400 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 401 |   if (*name == 'I') { | 
 | 402 |     state_stack_.push(cur_state_); | 
 | 403 |     cur_state_.Clear(); | 
 | 404 |  | 
 | 405 |     parse_funcs_.push_back(parse_func_); | 
 | 406 |     parse_func_ = &Demangler::ParseFunctionNameTemplate; | 
 | 407 |     return name + 1; | 
 | 408 |   } | 
 | 409 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 410 |   return ParseComplexString(name); | 
 | 411 | } | 
 | 412 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 413 | const char* Demangler::ParseFunctionNameTemplate(const char* name) { | 
 | 414 |   if (*name == 'E' && name[1] == 'E') { | 
 | 415 |     // Only consider this a template with saves if it is right before | 
 | 416 |     // the end of the name. | 
 | 417 |     template_found_ = true; | 
 | 418 |     template_saves_ = cur_state_.args; | 
 | 419 |   } | 
 | 420 |   return ParseTemplateArgumentsComplex(name); | 
 | 421 | } | 
 | 422 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 423 | const char* Demangler::ParseComplexArgument(const char* name) { | 
 | 424 |   if (*name == 'E') { | 
 | 425 |     if (parse_funcs_.empty()) { | 
 | 426 |       return nullptr; | 
 | 427 |     } | 
 | 428 |     parse_func_ = parse_funcs_.back(); | 
 | 429 |     parse_funcs_.pop_back(); | 
 | 430 |  | 
 | 431 |     AppendArgument(cur_state_.str); | 
 | 432 |     cur_state_.str.clear(); | 
 | 433 |  | 
 | 434 |     return name + 1; | 
 | 435 |   } | 
 | 436 |  | 
 | 437 |   return ParseComplexString(name); | 
 | 438 | } | 
 | 439 |  | 
 | 440 | void Demangler::FinalizeTemplate() { | 
 | 441 |   std::string arg_str(GetArgumentsString()); | 
 | 442 |   cur_state_ = state_stack_.top(); | 
 | 443 |   state_stack_.pop(); | 
 | 444 |   cur_state_.str += '<' + arg_str + '>'; | 
 | 445 | } | 
 | 446 |  | 
 | 447 | const char* Demangler::ParseComplexString(const char* name) { | 
 | 448 |   if (*name == 'S') { | 
 | 449 |     name++; | 
 | 450 |     if (*name == 't') { | 
 | 451 |       AppendCurrent("std"); | 
 | 452 |       return name + 1; | 
 | 453 |     } | 
 | 454 |     return ParseS(name); | 
 | 455 |   } | 
 | 456 |   if (*name == 'L') { | 
 | 457 |     name++; | 
 | 458 |     if (!std::isdigit(*name)) { | 
 | 459 |       return nullptr; | 
 | 460 |     } | 
 | 461 |   } | 
 | 462 |   if (std::isdigit(*name)) { | 
 | 463 |     std::string str; | 
 | 464 |     name = GetStringFromLength(name, &str); | 
 | 465 |     if (name == nullptr) { | 
 | 466 |       return name; | 
 | 467 |     } | 
 | 468 |     AppendCurrent(str); | 
 | 469 |     Save(cur_state_.str, true); | 
 | 470 |     cur_state_.last_save = std::move(str); | 
 | 471 |     return name; | 
 | 472 |   } | 
 | 473 |   if (*name == 'D') { | 
 | 474 |     name++; | 
 | 475 |     if (saves_.empty() || (*name != '0' && *name != '1' && *name != '2' | 
 | 476 |         && *name != '5')) { | 
 | 477 |       return nullptr; | 
 | 478 |     } | 
 | 479 |     last_save_name_ = false; | 
 | 480 |     AppendCurrent("~" + cur_state_.last_save); | 
 | 481 |     return name + 1; | 
 | 482 |   } | 
 | 483 |   if (*name == 'C') { | 
 | 484 |     name++; | 
 | 485 |     if (saves_.empty() || (*name != '1' && *name != '2' && *name != '3' | 
 | 486 |         && *name != '5')) { | 
 | 487 |       return nullptr; | 
 | 488 |     } | 
 | 489 |     last_save_name_ = false; | 
 | 490 |     AppendCurrent(cur_state_.last_save); | 
 | 491 |     return name + 1; | 
 | 492 |   } | 
 | 493 |   if (*name == 'K') { | 
 | 494 |     cur_state_.suffixes.push_back(" const"); | 
 | 495 |     return name + 1; | 
 | 496 |   } | 
 | 497 |   if (*name == 'V') { | 
 | 498 |     cur_state_.suffixes.push_back(" volatile"); | 
 | 499 |     return name + 1; | 
 | 500 |   } | 
 | 501 |   if (*name == 'I') { | 
 | 502 |     // Save the current argument state. | 
 | 503 |     state_stack_.push(cur_state_); | 
 | 504 |     cur_state_.Clear(); | 
 | 505 |  | 
 | 506 |     parse_funcs_.push_back(parse_func_); | 
 | 507 |     parse_func_ = &Demangler::ParseTemplateArgumentsComplex; | 
 | 508 |     return name + 1; | 
 | 509 |   } | 
 | 510 |   name = AppendOperatorString(name); | 
 | 511 |   if (name != nullptr) { | 
 | 512 |     Save(cur_state_.str, true); | 
 | 513 |   } | 
 | 514 |   return name; | 
 | 515 | } | 
 | 516 |  | 
 | 517 | void Demangler::AppendArgument(const std::string& str) { | 
 | 518 |   std::string arg(str); | 
 | 519 |   while (!cur_state_.suffixes.empty()) { | 
 | 520 |     arg += cur_state_.suffixes.back(); | 
 | 521 |     cur_state_.suffixes.pop_back(); | 
 | 522 |     Save(arg, false); | 
 | 523 |   } | 
 | 524 |   cur_state_.args.push_back(arg); | 
 | 525 | } | 
 | 526 |  | 
 | 527 | const char* Demangler::ParseFunctionArgument(const char* name) { | 
 | 528 |   if (*name == 'E') { | 
 | 529 |     // The first argument is the function modifier. | 
 | 530 |     // The second argument is the function type. | 
 | 531 |     // The third argument is the return type of the function. | 
 | 532 |     // The rest of the arguments are the function arguments. | 
 | 533 |     size_t num_args = cur_state_.args.size(); | 
 | 534 |     if (num_args < 4) { | 
 | 535 |       return nullptr; | 
 | 536 |     } | 
 | 537 |     std::string function_modifier = cur_state_.args[0]; | 
 | 538 |     std::string function_type = cur_state_.args[1]; | 
 | 539 |  | 
 | 540 |     std::string str = cur_state_.args[2] + ' '; | 
 | 541 |     if (!cur_state_.args[1].empty()) { | 
 | 542 |       str += '(' + cur_state_.args[1] + ')'; | 
 | 543 |     } | 
 | 544 |  | 
 | 545 |     if (num_args == 4 && cur_state_.args[3] == "void") { | 
 | 546 |       str += "()"; | 
 | 547 |     } else { | 
 | 548 |       str += '(' + cur_state_.args[3]; | 
 | 549 |       for (size_t i = 4; i < num_args; i++) { | 
 | 550 |         str += ", " + cur_state_.args[i]; | 
 | 551 |       } | 
 | 552 |       str += ')'; | 
 | 553 |     } | 
 | 554 |     str += cur_state_.args[0]; | 
 | 555 |  | 
 | 556 |     cur_state_ = state_stack_.top(); | 
 | 557 |     state_stack_.pop(); | 
 | 558 |     cur_state_.args.emplace_back(std::move(str)); | 
 | 559 |  | 
 | 560 |     parse_func_ = parse_funcs_.back(); | 
 | 561 |     parse_funcs_.pop_back(); | 
 | 562 |     return name + 1; | 
 | 563 |   } | 
 | 564 |   return ParseArguments(name); | 
 | 565 | } | 
 | 566 |  | 
 | 567 | const char* Demangler::ParseArguments(const char* name) { | 
 | 568 |   switch (*name) { | 
 | 569 |   case 'P': | 
 | 570 |     cur_state_.suffixes.push_back("*"); | 
 | 571 |     return name + 1; | 
 | 572 |  | 
 | 573 |   case 'R': | 
 | 574 |     // This should always be okay because the string is guaranteed to have | 
 | 575 |     // at least two characters before this. A mangled string always starts | 
 | 576 |     // with _Z. | 
 | 577 |     if (name[-1] != 'R') { | 
 | 578 |       // Multiple 'R's in a row only add a single &. | 
 | 579 |       cur_state_.suffixes.push_back("&"); | 
 | 580 |     } | 
 | 581 |     return name + 1; | 
 | 582 |  | 
| Elliott Hughes | d7bb826 | 2018-02-09 17:30:14 -0800 | [diff] [blame] | 583 |   case 'O': | 
 | 584 |     cur_state_.suffixes.push_back("&&"); | 
 | 585 |     return name + 1; | 
 | 586 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 587 |   case 'K': | 
 | 588 |   case 'V': { | 
 | 589 |     const char* suffix; | 
 | 590 |     if (*name == 'K') { | 
 | 591 |       suffix = " const"; | 
 | 592 |     } else { | 
 | 593 |       suffix = " volatile"; | 
 | 594 |     } | 
| Christopher Ferris | 15d2e42 | 2017-05-31 14:40:15 -0700 | [diff] [blame] | 595 |     if (!cur_state_.suffixes.empty() && (name[-1] == 'K' || name[-1] == 'V')) { | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 596 |       // Special case, const/volatile apply as a single entity. | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 597 |       size_t index = cur_state_.suffixes.size(); | 
 | 598 |       cur_state_.suffixes[index-1].insert(0, suffix); | 
 | 599 |     } else { | 
 | 600 |       cur_state_.suffixes.push_back(suffix); | 
 | 601 |     } | 
 | 602 |     return name + 1; | 
 | 603 |   } | 
 | 604 |  | 
 | 605 |   case 'F': { | 
 | 606 |     std::string function_modifier; | 
 | 607 |     std::string function_type; | 
 | 608 |     if (!cur_state_.suffixes.empty()) { | 
 | 609 |       // If the first element starts with a ' ', then this modifies the | 
 | 610 |       // function itself. | 
 | 611 |       if (cur_state_.suffixes.back()[0] == ' ') { | 
 | 612 |         function_modifier = cur_state_.suffixes.back(); | 
 | 613 |         cur_state_.suffixes.pop_back(); | 
 | 614 |       } | 
 | 615 |       while (!cur_state_.suffixes.empty()) { | 
 | 616 |         function_type += cur_state_.suffixes.back(); | 
 | 617 |         cur_state_.suffixes.pop_back(); | 
 | 618 |       } | 
 | 619 |     } | 
 | 620 |  | 
 | 621 |     state_stack_.push(cur_state_); | 
 | 622 |  | 
 | 623 |     cur_state_.Clear(); | 
 | 624 |  | 
 | 625 |     // The function parameter has this format: | 
 | 626 |     //   First argument is the function modifier. | 
 | 627 |     //   Second argument is the function type. | 
 | 628 |     //   Third argument will be the return function type but has not | 
 | 629 |     //     been parsed yet. | 
 | 630 |     //   Any other parameters are the arguments to the function. There | 
 | 631 |     //     must be at least one or this isn't valid. | 
 | 632 |     cur_state_.args.push_back(function_modifier); | 
 | 633 |     cur_state_.args.push_back(function_type); | 
 | 634 |  | 
 | 635 |     parse_funcs_.push_back(parse_func_); | 
 | 636 |     parse_func_ = &Demangler::ParseFunctionArgument; | 
 | 637 |     return name + 1; | 
 | 638 |   } | 
 | 639 |  | 
 | 640 |   case 'N': | 
 | 641 |     parse_funcs_.push_back(parse_func_); | 
 | 642 |     parse_func_ = &Demangler::ParseComplexArgument; | 
 | 643 |     return name + 1; | 
 | 644 |  | 
 | 645 |   case 'S': | 
 | 646 |     name++; | 
 | 647 |     if (*name == 't') { | 
 | 648 |       cur_state_.str = "std::"; | 
 | 649 |       return name + 1; | 
 | 650 |     } | 
 | 651 |     name = ParseS(name); | 
 | 652 |     if (name == nullptr) { | 
 | 653 |       return nullptr; | 
 | 654 |     } | 
 | 655 |     AppendArgument(cur_state_.str); | 
 | 656 |     cur_state_.str.clear(); | 
 | 657 |     return name; | 
 | 658 |  | 
 | 659 |   case 'D': | 
 | 660 |     name++; | 
 | 661 |     if (*name >= 'a' && *name <= 'z') { | 
 | 662 |       const char* arg = Demangler::kDTypes[*name - 'a']; | 
 | 663 |       if (arg == nullptr) { | 
 | 664 |         return nullptr; | 
 | 665 |       } | 
 | 666 |       AppendArgument(arg); | 
 | 667 |       return name + 1; | 
 | 668 |     } | 
 | 669 |     return nullptr; | 
 | 670 |  | 
 | 671 |   case 'I': | 
 | 672 |     // Save the current argument state. | 
 | 673 |     state_stack_.push(cur_state_); | 
 | 674 |     cur_state_.Clear(); | 
 | 675 |  | 
 | 676 |     parse_funcs_.push_back(parse_func_); | 
 | 677 |     parse_func_ = &Demangler::ParseTemplateArguments; | 
 | 678 |     return name + 1; | 
 | 679 |  | 
 | 680 |   case 'v': | 
 | 681 |     AppendArgument("void"); | 
 | 682 |     return name + 1; | 
 | 683 |  | 
 | 684 |   default: | 
 | 685 |     if (*name >= 'a' && *name <= 'z') { | 
 | 686 |       const char* arg = Demangler::kTypes[*name - 'a']; | 
 | 687 |       if (arg == nullptr) { | 
 | 688 |         return nullptr; | 
 | 689 |       } | 
 | 690 |       AppendArgument(arg); | 
 | 691 |       return name + 1; | 
 | 692 |     } else if (std::isdigit(*name)) { | 
 | 693 |       std::string arg = cur_state_.str; | 
 | 694 |       name = GetStringFromLength(name, &arg); | 
 | 695 |       if (name == nullptr) { | 
 | 696 |         return nullptr; | 
 | 697 |       } | 
 | 698 |       Save(arg, true); | 
 | 699 |       if (*name == 'I') { | 
 | 700 |         // There is one case where this argument is not complete, and that's | 
 | 701 |         // where this is a template argument. | 
 | 702 |         cur_state_.str = arg; | 
 | 703 |       } else { | 
 | 704 |         AppendArgument(arg); | 
 | 705 |         cur_state_.str.clear(); | 
 | 706 |       } | 
 | 707 |       return name; | 
| Elliott Hughes | d7bb826 | 2018-02-09 17:30:14 -0800 | [diff] [blame] | 708 |     } else if (strcmp(name, ".cfi") == 0) { | 
 | 709 |       function_suffix_ += " [clone .cfi]"; | 
 | 710 |       return name + 4; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 711 |     } | 
 | 712 |   } | 
 | 713 |   return nullptr; | 
 | 714 | } | 
 | 715 |  | 
| Christopher Ferris | 0523275 | 2017-10-11 15:22:29 -0700 | [diff] [blame] | 716 | const char* Demangler::ParseTemplateLiteral(const char* name) { | 
 | 717 |   if (*name == 'E') { | 
 | 718 |     parse_func_ = parse_funcs_.back(); | 
 | 719 |     parse_funcs_.pop_back(); | 
 | 720 |     return name + 1; | 
 | 721 |   } | 
 | 722 |   // Only understand boolean values with 0 or 1. | 
 | 723 |   if (*name == 'b') { | 
 | 724 |     name++; | 
 | 725 |     if (*name == '0') { | 
 | 726 |       AppendArgument("false"); | 
 | 727 |       cur_state_.str.clear(); | 
 | 728 |     } else if (*name == '1') { | 
 | 729 |       AppendArgument("true"); | 
 | 730 |       cur_state_.str.clear(); | 
 | 731 |     } else { | 
 | 732 |       return nullptr; | 
 | 733 |     } | 
 | 734 |     return name + 1; | 
 | 735 |   } | 
 | 736 |   return nullptr; | 
 | 737 | } | 
 | 738 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 739 | const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { | 
 | 740 |   if (*name == 'E') { | 
 | 741 |     if (parse_funcs_.empty()) { | 
 | 742 |       return nullptr; | 
 | 743 |     } | 
 | 744 |     parse_func_ = parse_funcs_.back(); | 
 | 745 |     parse_funcs_.pop_back(); | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 746 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 747 |     FinalizeTemplate(); | 
 | 748 |     Save(cur_state_.str, false); | 
 | 749 |     return name + 1; | 
| Christopher Ferris | 0523275 | 2017-10-11 15:22:29 -0700 | [diff] [blame] | 750 |   } else if (*name == 'L') { | 
 | 751 |     // Literal value for a template. | 
 | 752 |     parse_funcs_.push_back(parse_func_); | 
 | 753 |     parse_func_ = &Demangler::ParseTemplateLiteral; | 
 | 754 |     return name + 1; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 755 |   } | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 756 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 757 |   return ParseArguments(name); | 
 | 758 | } | 
 | 759 |  | 
 | 760 | const char* Demangler::ParseTemplateArguments(const char* name) { | 
 | 761 |   if (*name == 'E') { | 
 | 762 |     if (parse_funcs_.empty()) { | 
 | 763 |       return nullptr; | 
 | 764 |     } | 
 | 765 |     parse_func_ = parse_funcs_.back(); | 
 | 766 |     parse_funcs_.pop_back(); | 
 | 767 |     FinalizeTemplate(); | 
 | 768 |     AppendArgument(cur_state_.str); | 
 | 769 |     cur_state_.str.clear(); | 
 | 770 |     return name + 1; | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 771 |   } else if (*name == 'L') { | 
 | 772 |     // Literal value for a template. | 
 | 773 |     parse_funcs_.push_back(parse_func_); | 
 | 774 |     parse_func_ = &Demangler::ParseTemplateLiteral; | 
 | 775 |     return name + 1; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 776 |   } | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 777 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 778 |   return ParseArguments(name); | 
 | 779 | } | 
 | 780 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 781 | const char* Demangler::ParseFunctionTemplateArguments(const char* name) { | 
 | 782 |   if (*name == 'E') { | 
 | 783 |     parse_func_ = parse_funcs_.back(); | 
 | 784 |     parse_funcs_.pop_back(); | 
 | 785 |  | 
 | 786 |     function_name_ += '<' + GetArgumentsString() + '>'; | 
 | 787 |     template_found_ = true; | 
 | 788 |     template_saves_ = cur_state_.args; | 
 | 789 |     cur_state_.Clear(); | 
 | 790 |     return name + 1; | 
 | 791 |   } | 
 | 792 |   return ParseTemplateArgumentsComplex(name); | 
 | 793 | } | 
 | 794 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 795 | const char* Demangler::FindFunctionName(const char* name) { | 
| Christopher Ferris | 5a72ea0 | 2017-11-01 16:22:09 -0700 | [diff] [blame] | 796 |   if (*name == 'T') { | 
 | 797 |     // non-virtual thunk, verify that it matches one of these patterns: | 
 | 798 |     //   Thn[0-9]+_ | 
 | 799 |     //   Th[0-9]+_ | 
 | 800 |     //   Thn_ | 
 | 801 |     //   Th_ | 
 | 802 |     name++; | 
 | 803 |     if (*name != 'h') { | 
 | 804 |       return nullptr; | 
 | 805 |     } | 
 | 806 |     name++; | 
 | 807 |     if (*name == 'n') { | 
 | 808 |       name++; | 
 | 809 |     } | 
 | 810 |     while (std::isdigit(*name)) { | 
 | 811 |       name++; | 
 | 812 |     } | 
 | 813 |     if (*name != '_') { | 
 | 814 |       return nullptr; | 
 | 815 |     } | 
 | 816 |     function_name_ = "non-virtual thunk to "; | 
 | 817 |     return name + 1; | 
 | 818 |   } | 
 | 819 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 820 |   if (*name == 'N') { | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 821 |     parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel); | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 822 |     parse_func_ = &Demangler::ParseFunctionName; | 
 | 823 |     return name + 1; | 
 | 824 |   } | 
 | 825 |  | 
| Elliott Hughes | d7bb826 | 2018-02-09 17:30:14 -0800 | [diff] [blame] | 826 |   if (*name == 'S') { | 
 | 827 |     name++; | 
 | 828 |     if (*name == 't') { | 
 | 829 |       function_name_ = "std::"; | 
 | 830 |       name++; | 
 | 831 |     } else { | 
 | 832 |       return nullptr; | 
 | 833 |     } | 
 | 834 |   } | 
 | 835 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 836 |   if (std::isdigit(*name)) { | 
 | 837 |     name = GetStringFromLength(name, &function_name_); | 
| Christopher Ferris | 4504bba | 2017-06-01 17:37:09 -0700 | [diff] [blame] | 838 |   } else if (*name == 'L' && std::isdigit(name[1])) { | 
 | 839 |     name = GetStringFromLength(name + 1, &function_name_); | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 840 |   } else { | 
 | 841 |     name = AppendOperatorString(name); | 
 | 842 |     function_name_ = cur_state_.str; | 
 | 843 |   } | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 844 |   cur_state_.Clear(); | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 845 |  | 
 | 846 |   // Check for a template argument, which will still be part of the function | 
 | 847 |   // name. | 
 | 848 |   if (name != nullptr && *name == 'I') { | 
 | 849 |     parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel); | 
 | 850 |     parse_func_ = &Demangler::ParseFunctionTemplateArguments; | 
 | 851 |     return name + 1; | 
 | 852 |   } | 
 | 853 |   parse_func_ = &Demangler::ParseArgumentsAtTopLevel; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 854 |   return name; | 
 | 855 | } | 
 | 856 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 857 | const char* Demangler::ParseArgumentsAtTopLevel(const char* name) { | 
 | 858 |   // At the top level is the only place where T is allowed. | 
 | 859 |   if (*name == 'T') { | 
 | 860 |     name++; | 
 | 861 |     name = ParseT(name); | 
 | 862 |     if (name == nullptr) { | 
 | 863 |       return nullptr; | 
 | 864 |     } | 
 | 865 |     AppendArgument(cur_state_.str); | 
 | 866 |     cur_state_.str.clear(); | 
 | 867 |     return name; | 
 | 868 |   } | 
 | 869 |  | 
 | 870 |   return Demangler::ParseArguments(name); | 
 | 871 | } | 
 | 872 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 873 | std::string Demangler::Parse(const char* name, size_t max_length) { | 
 | 874 |   if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') { | 
 | 875 |     // Name is not mangled. | 
 | 876 |     return name; | 
 | 877 |   } | 
 | 878 |  | 
 | 879 |   Clear(); | 
 | 880 |  | 
 | 881 |   parse_func_ = &Demangler::FindFunctionName; | 
 | 882 |   parse_funcs_.push_back(&Demangler::Fail); | 
 | 883 |   const char* cur_name = name + 2; | 
 | 884 |   while (cur_name != nullptr && *cur_name != '\0' | 
 | 885 |       && static_cast<size_t>(cur_name - name) < max_length) { | 
 | 886 |     cur_name = (this->*parse_func_)(cur_name); | 
 | 887 |   } | 
| Christopher Ferris | 15d2e42 | 2017-05-31 14:40:15 -0700 | [diff] [blame] | 888 |   if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty() || | 
 | 889 |       !cur_state_.suffixes.empty()) { | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 890 |     return name; | 
 | 891 |   } | 
 | 892 |  | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 893 |   std::string return_type; | 
 | 894 |   if (template_found_) { | 
 | 895 |     // Only a single argument with a template is not allowed. | 
 | 896 |     if (cur_state_.args.size() == 1) { | 
 | 897 |       return name; | 
 | 898 |     } | 
 | 899 |  | 
 | 900 |     // If there are at least two arguments, this template has a return type. | 
 | 901 |     if (cur_state_.args.size() > 1) { | 
 | 902 |       // The first argument will be the return value. | 
 | 903 |       return_type = cur_state_.args[0] + ' '; | 
 | 904 |       cur_state_.args.erase(cur_state_.args.begin()); | 
 | 905 |     } | 
 | 906 |   } | 
 | 907 |  | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 908 |   std::string arg_str; | 
 | 909 |   if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") { | 
 | 910 |     // If the only argument is void, then don't print any args. | 
 | 911 |     arg_str = "()"; | 
 | 912 |   } else { | 
 | 913 |     arg_str = GetArgumentsString(); | 
 | 914 |     if (!arg_str.empty()) { | 
 | 915 |       arg_str = '(' + arg_str + ')'; | 
 | 916 |     } | 
 | 917 |   } | 
| Christopher Ferris | 584333e | 2017-10-27 12:29:02 -0700 | [diff] [blame] | 918 |   return return_type + function_name_ + arg_str + function_suffix_; | 
| Christopher Ferris | 9323b72 | 2017-03-03 17:43:14 -0800 | [diff] [blame] | 919 | } | 
 | 920 |  | 
 | 921 | std::string demangle(const char* name) { | 
 | 922 |   Demangler demangler; | 
 | 923 |   return demangler.Parse(name); | 
 | 924 | } |