1 //===--- DLangDemangle.cpp ------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines a demangler for the D programming language as specified 11 /// in the ABI specification, available at: 12 /// https://dlang.org/spec/abi.html#name_mangling 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Demangle/Demangle.h" 17 #include "llvm/Demangle/StringView.h" 18 #include "llvm/Demangle/Utility.h" 19 20 #include <cctype> 21 #include <cstring> 22 #include <limits> 23 24 using namespace llvm; 25 using llvm::itanium_demangle::OutputBuffer; 26 using llvm::itanium_demangle::StringView; 27 28 namespace { 29 30 /// Demangle information structure. 31 struct Demangler { 32 /// Initialize the information structure we use to pass around information. 33 /// 34 /// \param Mangled String to demangle. 35 Demangler(const char *Mangled); 36 37 /// Extract and demangle the mangled symbol and append it to the output 38 /// string. 39 /// 40 /// \param Demangled Output buffer to write the demangled name. 41 /// 42 /// \return The remaining string on success or nullptr on failure. 43 /// 44 /// \see https://dlang.org/spec/abi.html#name_mangling . 45 /// \see https://dlang.org/spec/abi.html#MangledName . 46 const char *parseMangle(OutputBuffer *Demangled); 47 48 private: 49 /// Extract and demangle a given mangled symbol and append it to the output 50 /// string. 51 /// 52 /// \param Demangled output buffer to write the demangled name. 53 /// \param Mangled mangled symbol to be demangled. 54 /// 55 /// \return The remaining string on success or nullptr on failure. 56 /// 57 /// \see https://dlang.org/spec/abi.html#name_mangling . 58 /// \see https://dlang.org/spec/abi.html#MangledName . 59 const char *parseMangle(OutputBuffer *Demangled, const char *Mangled); 60 61 /// Extract the number from a given string. 62 /// 63 /// \param Mangled string to extract the number. 64 /// \param Ret assigned result value. 65 /// 66 /// \return The remaining string on success or nullptr on failure. 67 /// 68 /// \note A result larger than UINT_MAX is considered a failure. 69 /// 70 /// \see https://dlang.org/spec/abi.html#Number . 71 const char *decodeNumber(const char *Mangled, unsigned long *Ret); 72 73 /// Extract the back reference position from a given string. 74 /// 75 /// \param Mangled string to extract the back reference position. 76 /// \param Ret assigned result value. 77 /// 78 /// \return the remaining string on success or nullptr on failure. 79 /// 80 /// \note Ret is always >= 0 on success, and unspecified on failure 81 /// 82 /// \see https://dlang.org/spec/abi.html#back_ref . 83 /// \see https://dlang.org/spec/abi.html#NumberBackRef . 84 const char *decodeBackrefPos(const char *Mangled, long &Ret); 85 86 /// Extract the symbol pointed by the back reference form a given string. 87 /// 88 /// \param Mangled string to extract the back reference position. 89 /// \param Ret assigned result value. 90 /// 91 /// \return the remaining string on success or nullptr on failure. 92 /// 93 /// \see https://dlang.org/spec/abi.html#back_ref . 94 const char *decodeBackref(const char *Mangled, const char *&Ret); 95 96 /// Extract and demangle backreferenced symbol from a given mangled symbol 97 /// and append it to the output string. 98 /// 99 /// \param Demangled output buffer to write the demangled name. 100 /// \param Mangled mangled symbol to be demangled. 101 /// 102 /// \return the remaining string on success or nullptr on failure. 103 /// 104 /// \see https://dlang.org/spec/abi.html#back_ref . 105 /// \see https://dlang.org/spec/abi.html#IdentifierBackRef . 106 const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled); 107 108 /// Check whether it is the beginning of a symbol name. 109 /// 110 /// \param Mangled string to extract the symbol name. 111 /// 112 /// \return true on success, false otherwise. 113 /// 114 /// \see https://dlang.org/spec/abi.html#SymbolName . 115 bool isSymbolName(const char *Mangled); 116 117 /// Extract and demangle an identifier from a given mangled symbol append it 118 /// to the output string. 119 /// 120 /// \param Demangled Output buffer to write the demangled name. 121 /// \param Mangled Mangled symbol to be demangled. 122 /// 123 /// \return The remaining string on success or nullptr on failure. 124 /// 125 /// \see https://dlang.org/spec/abi.html#SymbolName . 126 const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled); 127 128 /// Extract and demangle the plain identifier from a given mangled symbol and 129 /// prepend/append it to the output string, with a special treatment for some 130 /// magic compiler generated symbols. 131 /// 132 /// \param Demangled Output buffer to write the demangled name. 133 /// \param Mangled Mangled symbol to be demangled. 134 /// \param Len Length of the mangled symbol name. 135 /// 136 /// \return The remaining string on success or nullptr on failure. 137 /// 138 /// \see https://dlang.org/spec/abi.html#LName . 139 const char *parseLName(OutputBuffer *Demangled, const char *Mangled, 140 unsigned long Len); 141 142 /// Extract and demangle the qualified symbol from a given mangled symbol 143 /// append it to the output string. 144 /// 145 /// \param Demangled Output buffer to write the demangled name. 146 /// \param Mangled Mangled symbol to be demangled. 147 /// 148 /// \return The remaining string on success or nullptr on failure. 149 /// 150 /// \see https://dlang.org/spec/abi.html#QualifiedName . 151 const char *parseQualified(OutputBuffer *Demangled, const char *Mangled); 152 153 /// Extract and demangle a type from a given mangled symbol append it to 154 /// the output string. 155 /// 156 /// \param Mangled mangled symbol to be demangled. 157 /// 158 /// \return the remaining string on success or nullptr on failure. 159 /// 160 /// \see https://dlang.org/spec/abi.html#Type . 161 const char *parseType(const char *Mangled); 162 163 /// The string we are demangling. 164 const char *Str; 165 }; 166 167 } // namespace 168 169 const char *Demangler::decodeNumber(const char *Mangled, unsigned long *Ret) { 170 // Return nullptr if trying to extract something that isn't a digit. 171 if (Mangled == nullptr || !std::isdigit(*Mangled)) 172 return nullptr; 173 174 unsigned long Val = 0; 175 176 do { 177 unsigned long Digit = Mangled[0] - '0'; 178 179 // Check for overflow. 180 if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10) 181 return nullptr; 182 183 Val = Val * 10 + Digit; 184 ++Mangled; 185 } while (std::isdigit(*Mangled)); 186 187 if (*Mangled == '\0') 188 return nullptr; 189 190 *Ret = Val; 191 return Mangled; 192 } 193 194 const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) { 195 // Return nullptr if trying to extract something that isn't a digit 196 if (Mangled == nullptr || !std::isalpha(*Mangled)) 197 return nullptr; 198 199 // Any identifier or non-basic type that has been emitted to the mangled 200 // symbol before will not be emitted again, but is referenced by a special 201 // sequence encoding the relative position of the original occurrence in the 202 // mangled symbol name. 203 // Numbers in back references are encoded with base 26 by upper case letters 204 // A-Z for higher digits but lower case letters a-z for the last digit. 205 // NumberBackRef: 206 // [a-z] 207 // [A-Z] NumberBackRef 208 // ^ 209 unsigned long Val = 0; 210 211 while (std::isalpha(*Mangled)) { 212 // Check for overflow 213 if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26) 214 break; 215 216 Val *= 26; 217 218 if (Mangled[0] >= 'a' && Mangled[0] <= 'z') { 219 Val += Mangled[0] - 'a'; 220 if ((long)Val <= 0) 221 break; 222 Ret = Val; 223 return Mangled + 1; 224 } 225 226 Val += Mangled[0] - 'A'; 227 ++Mangled; 228 } 229 230 return nullptr; 231 } 232 233 const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) { 234 assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!"); 235 Ret = nullptr; 236 237 // Position of 'Q' 238 const char *Qpos = Mangled; 239 long RefPos; 240 ++Mangled; 241 242 Mangled = decodeBackrefPos(Mangled, RefPos); 243 if (Mangled == nullptr) 244 return nullptr; 245 246 if (RefPos > Qpos - Str) 247 return nullptr; 248 249 // Set the position of the back reference. 250 Ret = Qpos - RefPos; 251 252 return Mangled; 253 } 254 255 const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled, 256 const char *Mangled) { 257 // An identifier back reference always points to a digit 0 to 9. 258 // IdentifierBackRef: 259 // Q NumberBackRef 260 // ^ 261 const char *Backref; 262 unsigned long Len; 263 264 // Get position of the back reference 265 Mangled = decodeBackref(Mangled, Backref); 266 267 // Must point to a simple identifier 268 Backref = decodeNumber(Backref, &Len); 269 if (Backref == nullptr || strlen(Backref) < Len) 270 return nullptr; 271 272 Backref = parseLName(Demangled, Backref, Len); 273 if (Backref == nullptr) 274 return nullptr; 275 276 return Mangled; 277 } 278 279 bool Demangler::isSymbolName(const char *Mangled) { 280 long Ret; 281 const char *Qref = Mangled; 282 283 if (std::isdigit(*Mangled)) 284 return true; 285 286 // TODO: Handle template instances. 287 288 if (*Mangled != 'Q') 289 return false; 290 291 Mangled = decodeBackrefPos(Mangled + 1, Ret); 292 if (Mangled == nullptr || Ret > Qref - Str) 293 return false; 294 295 return std::isdigit(Qref[-Ret]); 296 } 297 298 const char *Demangler::parseMangle(OutputBuffer *Demangled, 299 const char *Mangled) { 300 // A D mangled symbol is comprised of both scope and type information. 301 // MangleName: 302 // _D QualifiedName Type 303 // _D QualifiedName Z 304 // ^ 305 // The caller should have guaranteed that the start pointer is at the 306 // above location. 307 // Note that type is never a function type, but only the return type of 308 // a function or the type of a variable. 309 Mangled += 2; 310 311 Mangled = parseQualified(Demangled, Mangled); 312 313 if (Mangled != nullptr) { 314 // Artificial symbols end with 'Z' and have no type. 315 if (*Mangled == 'Z') 316 ++Mangled; 317 else { 318 Mangled = parseType(Mangled); 319 } 320 } 321 322 return Mangled; 323 } 324 325 const char *Demangler::parseQualified(OutputBuffer *Demangled, 326 const char *Mangled) { 327 // Qualified names are identifiers separated by their encoded length. 328 // Nested functions also encode their argument types without specifying 329 // what they return. 330 // QualifiedName: 331 // SymbolFunctionName 332 // SymbolFunctionName QualifiedName 333 // ^ 334 // SymbolFunctionName: 335 // SymbolName 336 // SymbolName TypeFunctionNoReturn 337 // SymbolName M TypeFunctionNoReturn 338 // SymbolName M TypeModifiers TypeFunctionNoReturn 339 // The start pointer should be at the above location. 340 341 // Whether it has more than one symbol 342 size_t NotFirst = false; 343 do { 344 // Skip over anonymous symbols. 345 if (*Mangled == '0') { 346 do 347 ++Mangled; 348 while (*Mangled == '0'); 349 350 continue; 351 } 352 353 if (NotFirst) 354 *Demangled << '.'; 355 NotFirst = true; 356 357 Mangled = parseIdentifier(Demangled, Mangled); 358 359 } while (Mangled && isSymbolName(Mangled)); 360 361 return Mangled; 362 } 363 364 const char *Demangler::parseIdentifier(OutputBuffer *Demangled, 365 const char *Mangled) { 366 unsigned long Len; 367 368 if (Mangled == nullptr || *Mangled == '\0') 369 return nullptr; 370 371 if (*Mangled == 'Q') 372 return parseSymbolBackref(Demangled, Mangled); 373 374 // TODO: Parse lengthless template instances. 375 376 const char *Endptr = decodeNumber(Mangled, &Len); 377 378 if (Endptr == nullptr || Len == 0) 379 return nullptr; 380 381 if (strlen(Endptr) < Len) 382 return nullptr; 383 384 Mangled = Endptr; 385 386 // TODO: Parse template instances with a length prefix. 387 388 // There can be multiple different declarations in the same function that 389 // have the same mangled name. To make the mangled names unique, a fake 390 // parent in the form `__Sddd' is added to the symbol. 391 if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') { 392 const char *NumPtr = Mangled + 3; 393 while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr)) 394 ++NumPtr; 395 396 if (Mangled + Len == NumPtr) { 397 // Skip over the fake parent. 398 Mangled += Len; 399 return parseIdentifier(Demangled, Mangled); 400 } 401 402 // Else demangle it as a plain identifier. 403 } 404 405 return parseLName(Demangled, Mangled, Len); 406 } 407 408 const char *Demangler::parseType(const char *Mangled) { 409 if (*Mangled == '\0') 410 return nullptr; 411 412 switch (*Mangled) { 413 // TODO: Parse type qualifiers. 414 // TODO: Parse function types. 415 // TODO: Parse compound types. 416 // TODO: Parse delegate types. 417 // TODO: Parse tuple types. 418 419 // Basic types. 420 case 'i': 421 ++Mangled; 422 // TODO: Add type name dumping 423 return Mangled; 424 425 // TODO: Add support for the rest of the basic types. 426 // TODO: Parse back referenced types. 427 428 default: // unhandled. 429 return nullptr; 430 } 431 } 432 433 const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled, 434 unsigned long Len) { 435 switch (Len) { 436 case 6: 437 if (strncmp(Mangled, "__initZ", Len + 1) == 0) { 438 // The static initializer for a given symbol. 439 Demangled->prepend("initializer for "); 440 Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); 441 Mangled += Len; 442 return Mangled; 443 } 444 if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) { 445 // The vtable symbol for a given class. 446 Demangled->prepend("vtable for "); 447 Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); 448 Mangled += Len; 449 return Mangled; 450 } 451 break; 452 453 case 7: 454 if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) { 455 // The classinfo symbol for a given class. 456 Demangled->prepend("ClassInfo for "); 457 Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); 458 Mangled += Len; 459 return Mangled; 460 } 461 break; 462 463 case 11: 464 if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) { 465 // The interface symbol for a given class. 466 Demangled->prepend("Interface for "); 467 Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); 468 Mangled += Len; 469 return Mangled; 470 } 471 break; 472 473 case 12: 474 if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) { 475 // The ModuleInfo symbol for a given module. 476 Demangled->prepend("ModuleInfo for "); 477 Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1); 478 Mangled += Len; 479 return Mangled; 480 } 481 break; 482 } 483 484 *Demangled << StringView(Mangled, Len); 485 Mangled += Len; 486 487 return Mangled; 488 } 489 490 Demangler::Demangler(const char *Mangled) : Str(Mangled) {} 491 492 const char *Demangler::parseMangle(OutputBuffer *Demangled) { 493 return parseMangle(Demangled, this->Str); 494 } 495 496 char *llvm::dlangDemangle(const char *MangledName) { 497 if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0) 498 return nullptr; 499 500 OutputBuffer Demangled; 501 if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024)) 502 return nullptr; 503 504 if (strcmp(MangledName, "_Dmain") == 0) { 505 Demangled << "D main"; 506 } else { 507 508 Demangler D = Demangler(MangledName); 509 MangledName = D.parseMangle(&Demangled); 510 511 // Check that the entire symbol was successfully demangled. 512 if (MangledName == nullptr || *MangledName != '\0') { 513 std::free(Demangled.getBuffer()); 514 return nullptr; 515 } 516 } 517 518 // OutputBuffer's internal buffer is not null terminated and therefore we need 519 // to add it to comply with C null terminated strings. 520 if (Demangled.getCurrentPosition() > 0) { 521 Demangled << '\0'; 522 Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1); 523 return Demangled.getBuffer(); 524 } 525 526 std::free(Demangled.getBuffer()); 527 return nullptr; 528 } 529