1
0
mirror of synced 2025-02-17 18:59:21 +01:00

sys: Updated llvm demangler, now supports D-Lang and Rust symbols

This commit is contained in:
WerWolv 2022-08-09 13:51:03 +02:00
parent f1ec2ef0c4
commit 0192c791ce
30 changed files with 4807 additions and 2494 deletions

View File

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.16)
project(llvm-demangle)
set(CMAKE_CXX_STANDARD 17)
add_library(llvm-demangle STATIC
source/Demangle.cpp
source/DLangDemangle.cpp
source/ItaniumDemangle.cpp
source/MicrosoftDemangle.cpp
source/MicrosoftDemangleNodes.cpp
source/RustDemangle.cpp
)
target_include_directories(llvm-demangle PUBLIC include)

279
lib/external/llvm-demangle/LICENSE.TXT vendored Normal file
View File

@ -0,0 +1,279 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.

View File

@ -31,7 +31,6 @@ enum : int {
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
int *status);
enum MSDemangleFlags {
MSDF_None = 0,
MSDF_DumpBackrefs = 1 << 0,
@ -39,6 +38,7 @@ enum MSDemangleFlags {
MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4,
MSDF_NoVariableType = 1 << 5,
};
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
@ -53,9 +53,15 @@ enum MSDemangleFlags {
/// receives the size of the demangled string on output if n_buf is not nullptr.
/// status receives one of the demangle_ enum entries above if it's not nullptr.
/// Flags controls various details of the demangled representation.
char *microsoftDemangle(const char *mangled_name, size_t *n_read,
char *buf, size_t *n_buf,
int *status, MSDemangleFlags Flags = MSDF_None);
char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf,
size_t *n_buf, int *status,
MSDemangleFlags Flags = MSDF_None);
// Demangles a Rust v0 mangled symbol.
char *rustDemangle(const char *MangledName);
// Demangles a D mangled symbol.
char *dlangDemangle(const char *MangledName);
/// Attempt to demangle a string using different demangling schemes.
/// The function uses heuristics to determine which demangling scheme to use.
@ -64,6 +70,8 @@ char *microsoftDemangle(const char *mangled_name, size_t *n_read,
/// demangling occurred.
std::string demangle(const std::string &MangledName);
bool nonMicrosoftDemangle(const char *MangledName, std::string &Result);
/// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain
/// properties or partially printing the demangled name.
@ -115,6 +123,7 @@ struct ItaniumPartialDemangler {
bool isSpecialName() const;
~ItaniumPartialDemangler();
private:
void *RootNode;
void *Context;

View File

@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H
#define LLVM_DEMANGLE_COMPILER_H
#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H
#define LLVM_DEMANGLE_DEMANGLECONFIG_H
#ifndef __has_feature
#define __has_feature(x) 0

View File

@ -0,0 +1,95 @@
//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Define the demangler's node names
#ifndef NODE
#error Define NODE to handle nodes
#endif
NODE(NodeArrayNode)
NODE(DotSuffix)
NODE(VendorExtQualType)
NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
NODE(ObjCProtoName)
NODE(PointerType)
NODE(ReferenceType)
NODE(PointerToMemberType)
NODE(ArrayType)
NODE(FunctionType)
NODE(NoexceptSpec)
NODE(DynamicExceptionSpec)
NODE(FunctionEncoding)
NODE(LiteralOperator)
NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
NODE(VectorType)
NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
NODE(ParameterPack)
NODE(TemplateArgumentPack)
NODE(ParameterPackExpansion)
NODE(TemplateArgs)
NODE(ForwardTemplateReference)
NODE(NameWithTemplateArgs)
NODE(GlobalQualifiedName)
NODE(ExpandedSpecialSubstitution)
NODE(SpecialSubstitution)
NODE(CtorDtorName)
NODE(DtorName)
NODE(UnnamedTypeName)
NODE(ClosureTypeName)
NODE(StructuredBindingName)
NODE(BinaryExpr)
NODE(ArraySubscriptExpr)
NODE(PostfixExpr)
NODE(ConditionalExpr)
NODE(MemberExpr)
NODE(SubobjectExpr)
NODE(EnclosingExpr)
NODE(CastExpr)
NODE(SizeofParamPackExpr)
NODE(CallExpr)
NODE(NewExpr)
NODE(DeleteExpr)
NODE(PrefixExpr)
NODE(FunctionParam)
NODE(ConversionExpr)
NODE(PointerToMemberConversionExpr)
NODE(InitListExpr)
NODE(FoldExpr)
NODE(ThrowExpr)
NODE(BoolExpr)
NODE(StringLiteral)
NODE(LambdaExpr)
NODE(EnumLiteral)
NODE(IntegerLiteral)
NODE(FloatLiteral)
NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
#undef NODE

View File

@ -6,13 +6,11 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
#include <utility>
@ -275,4 +273,4 @@ private:
} // namespace ms_demangle
} // namespace llvm
#endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H

View File

@ -10,10 +10,9 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/StringView.h"
#include <array>
#include <cstdint>
@ -21,11 +20,11 @@
namespace llvm {
namespace itanium_demangle {
class OutputStream;
class OutputBuffer;
}
}
using llvm::itanium_demangle::OutputStream;
using llvm::itanium_demangle::OutputBuffer;
using llvm::itanium_demangle::StringView;
namespace llvm {
@ -67,6 +66,8 @@ enum class CallingConv : uint8_t {
Eabi,
Vectorcall,
Regcall,
Swift, // Clang-only
SwiftAsync, // Clang-only
};
enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
@ -78,6 +79,7 @@ enum OutputFlags {
OF_NoAccessSpecifier = 4,
OF_NoMemberType = 8,
OF_NoReturnType = 16,
OF_NoVariableType = 32,
};
// Types
@ -259,7 +261,7 @@ struct Node {
NodeKind kind() const { return Kind; }
virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;
virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0;
std::string toString(OutputFlags Flags = OF_Default) const;
@ -280,9 +282,7 @@ struct StructorIdentifierNode;
struct ThunkSignatureNode;
struct PointerTypeNode;
struct ArrayTypeNode;
struct CustomNode;
struct TagTypeNode;
struct IntrinsicTypeNode;
struct NodeArrayNode;
struct QualifiedNameNode;
struct TemplateParameterReferenceNode;
@ -298,12 +298,12 @@ struct SpecialTableSymbolNode;
struct TypeNode : public Node {
explicit TypeNode(NodeKind K) : Node(K) {}
virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;
virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;
virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0;
virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0;
void output(OutputStream &OS, OutputFlags Flags) const override {
outputPre(OS, Flags);
outputPost(OS, Flags);
void output(OutputBuffer &OB, OutputFlags Flags) const override {
outputPre(OB, Flags);
outputPost(OB, Flags);
}
Qualifiers Quals = Q_None;
@ -313,8 +313,8 @@ struct PrimitiveTypeNode : public TypeNode {
explicit PrimitiveTypeNode(PrimitiveKind K)
: TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override {}
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {}
PrimitiveKind PrimKind;
};
@ -323,8 +323,8 @@ struct FunctionSignatureNode : public TypeNode {
explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
// Valid if this FunctionTypeNode is the Pointee of a PointerType or
// MemberPointerType.
@ -357,13 +357,13 @@ struct IdentifierNode : public Node {
NodeArrayNode *TemplateParams = nullptr;
protected:
void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;
void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const;
};
struct VcallThunkIdentifierNode : public IdentifierNode {
VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint64_t OffsetInVTable = 0;
};
@ -372,7 +372,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode {
DynamicStructorIdentifierNode()
: IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
VariableSymbolNode *Variable = nullptr;
QualifiedNameNode *Name = nullptr;
@ -382,7 +382,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode {
struct NamedIdentifierNode : public IdentifierNode {
NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
StringView Name;
};
@ -392,7 +392,7 @@ struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
: IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
Operator(Operator) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
IntrinsicFunctionKind Operator;
};
@ -401,7 +401,7 @@ struct LiteralOperatorIdentifierNode : public IdentifierNode {
LiteralOperatorIdentifierNode()
: IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
StringView Name;
};
@ -410,7 +410,7 @@ struct LocalStaticGuardIdentifierNode : public IdentifierNode {
LocalStaticGuardIdentifierNode()
: IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
bool IsThread = false;
uint32_t ScopeIndex = 0;
@ -420,7 +420,7 @@ struct ConversionOperatorIdentifierNode : public IdentifierNode {
ConversionOperatorIdentifierNode()
: IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
// The type that this operator converts too.
TypeNode *TargetType = nullptr;
@ -432,7 +432,7 @@ struct StructorIdentifierNode : public IdentifierNode {
: IdentifierNode(NodeKind::StructorIdentifier),
IsDestructor(IsDestructor) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
// The name of the class that this is a structor of.
IdentifierNode *Class = nullptr;
@ -442,8 +442,8 @@ struct StructorIdentifierNode : public IdentifierNode {
struct ThunkSignatureNode : public FunctionSignatureNode {
ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
struct ThisAdjustor {
uint32_t StaticOffset = 0;
@ -457,8 +457,8 @@ struct ThunkSignatureNode : public FunctionSignatureNode {
struct PointerTypeNode : public TypeNode {
PointerTypeNode() : TypeNode(NodeKind::PointerType) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
// Is this a pointer, reference, or rvalue-reference?
PointerAffinity Affinity = PointerAffinity::None;
@ -474,8 +474,8 @@ struct PointerTypeNode : public TypeNode {
struct TagTypeNode : public TypeNode {
explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *QualifiedName = nullptr;
TagKind Tag;
@ -484,11 +484,11 @@ struct TagTypeNode : public TypeNode {
struct ArrayTypeNode : public TypeNode {
ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;
void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;
void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const;
void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const;
// A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]`
NodeArrayNode *Dimensions = nullptr;
@ -499,14 +499,14 @@ struct ArrayTypeNode : public TypeNode {
struct IntrinsicNode : public TypeNode {
IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}
void output(OutputStream &OS, OutputFlags Flags) const override {}
void output(OutputBuffer &OB, OutputFlags Flags) const override {}
};
struct CustomTypeNode : public TypeNode {
CustomTypeNode() : TypeNode(NodeKind::Custom) {}
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
IdentifierNode *Identifier = nullptr;
};
@ -514,9 +514,9 @@ struct CustomTypeNode : public TypeNode {
struct NodeArrayNode : public Node {
NodeArrayNode() : Node(NodeKind::NodeArray) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const;
void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const;
Node **Nodes = nullptr;
size_t Count = 0;
@ -525,7 +525,7 @@ struct NodeArrayNode : public Node {
struct QualifiedNameNode : public Node {
QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
NodeArrayNode *Components = nullptr;
@ -539,7 +539,7 @@ struct TemplateParameterReferenceNode : public Node {
TemplateParameterReferenceNode()
: Node(NodeKind::TemplateParameterReference) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
SymbolNode *Symbol = nullptr;
@ -554,7 +554,7 @@ struct IntegerLiteralNode : public Node {
IntegerLiteralNode(uint64_t Value, bool IsNegative)
: Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint64_t Value = 0;
bool IsNegative = false;
@ -564,7 +564,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode {
RttiBaseClassDescriptorNode()
: IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
uint32_t NVOffset = 0;
int32_t VBPtrOffset = 0;
@ -574,7 +574,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode {
struct SymbolNode : public Node {
explicit SymbolNode(NodeKind K) : Node(K) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *Name = nullptr;
};
@ -582,7 +582,7 @@ struct SpecialTableSymbolNode : public SymbolNode {
explicit SpecialTableSymbolNode()
: SymbolNode(NodeKind::SpecialTableSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
QualifiedNameNode *TargetName = nullptr;
Qualifiers Quals = Qualifiers::Q_None;
};
@ -591,7 +591,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode {
LocalStaticGuardVariableNode()
: SymbolNode(NodeKind::LocalStaticGuardVariable) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
bool IsVisible = false;
};
@ -599,7 +599,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode {
struct EncodedStringLiteralNode : public SymbolNode {
EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
StringView DecodedString;
bool IsTruncated = false;
@ -609,7 +609,7 @@ struct EncodedStringLiteralNode : public SymbolNode {
struct VariableSymbolNode : public SymbolNode {
VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
StorageClass SC = StorageClass::None;
TypeNode *Type = nullptr;
@ -618,7 +618,7 @@ struct VariableSymbolNode : public SymbolNode {
struct FunctionSymbolNode : public SymbolNode {
FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
void output(OutputStream &OS, OutputFlags Flags) const override;
void output(OutputBuffer &OB, OutputFlags Flags) const override;
FunctionSignatureNode *Signature = nullptr;
};

View File

@ -0,0 +1,61 @@
Itanium Name Demangler Library
==============================
Introduction
------------
This directory contains the generic itanium name demangler
library. The main purpose of the library is to demangle C++ symbols,
i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP
base ManglingParser to perform some simple analysis on the mangled
name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the
demangled AST.
Why are there multiple copies of the this library in the source tree?
---------------------------------------------------------------------
The canonical sources are in libcxxabi/src/demangle and some of the
files are copied to llvm/include/llvm/Demangle. The simple reason for
this comes from before the monorepo, and both [sub]projects need to
demangle symbols, but neither can depend on each other.
* libcxxabi needs the demangler to implement __cxa_demangle, which is
part of the itanium ABI spec.
* LLVM needs a copy for a bunch of places, and cannot rely on the
system's __cxa_demangle because it a) might not be available (i.e.,
on Windows), and b) may not be up-to-date on the latest language
features.
The copy of the demangler in LLVM has some extra stuff that aren't
needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler),
which depend on the shared generic components. Despite these
differences, we want to keep the "core" generic demangling library
identical between both copies to simplify development and testing.
If you're working on the generic library, then do the work first in
libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This
script takes as an optional argument the path to llvm, and copies the
changes you made to libcxxabi over. Note that this script just
blindly overwrites all changes to the generic library in llvm, so be
careful.
Because the core demangler needs to work in libcxxabi, everything
needs to be declared in an anonymous namespace (see
DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that
depends on the libcxx dylib.
FIXME: Now that LLVM is a monorepo, it should be possible to
de-duplicate this code, and have both LLVM and libcxxabi depend on a
shared demangler library.
Testing
-------
The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
llvm/unittest/Demangle. The llvm directory should only get tests for stuff not
included in the core library. In the future though, we should probably move all
the tests to LLVM.
It is also a really good idea to run libFuzzer after non-trivial changes, see
libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html.

View File

@ -1,5 +1,5 @@
//===--- StringView.h -------------------------------------------*- C++ -*-===//
//
//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@ -7,14 +7,16 @@
//===----------------------------------------------------------------------===//
//
// FIXME: Use std::string_view instead when we support C++17.
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#ifndef LLVM_DEMANGLE_STRINGVIEW_H
#define LLVM_DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <algorithm>
#include <cassert>
#include <cstring>
@ -36,29 +38,23 @@ public:
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const {
return StringView(begin() + From, size() - From);
StringView substr(size_t Pos, size_t Len = npos) const {
assert(Pos <= size());
if (Len > size() - Pos)
Len = size() - Pos;
return StringView(begin() + Pos, Len);
}
size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr.
if (FindBegin < size()) {
if (From < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
if (const void *P = ::memchr(First + From, C, size() - From))
return size_t(static_cast<const char *>(P) - First);
}
return npos;
}
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const {
if (N >= size())
N = size();
@ -105,7 +101,7 @@ public:
bool startsWith(StringView Str) const {
if (Str.size() > size())
return false;
return std::equal(Str.begin(), Str.end(), begin());
return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
}
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@ -118,7 +114,7 @@ public:
inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
}
DEMANGLE_NAMESPACE_END

View File

@ -0,0 +1,218 @@
//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler.
// There are two copies of this file in the source tree. The one in libcxxabi
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
// the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_UTILITY_H
#define LLVM_DEMANGLE_UTILITY_H
#include "StringView.h"
#include <array>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <exception>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputBuffer {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there are at least N more positions in the buffer.
void grow(size_t N) {
size_t Need = N + CurrentPosition;
if (Need > BufferCapacity) {
// Reduce the number of reallocations, with a bit of hysteresis. The
// number here is chosen so the first allocation will more-than-likely not
// allocate more than 1K.
Need += 1024 - 32;
BufferCapacity *= 2;
if (BufferCapacity < Need)
BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
std::array<char, 21> Temp;
char *TempPtr = Temp.data() + Temp.size();
// Output at least one character.
do {
*--TempPtr = char('0' + N % 10);
N /= 10;
} while (N);
// Add negative sign.
if (isNeg)
*--TempPtr = '-';
return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
}
public:
OutputBuffer(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputBuffer() = default;
// Non-copyable
OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
operator StringView() const { return StringView(Buffer, CurrentPosition); }
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
/// When zero, we're printing template args and '>' needs to be parenthesized.
/// Use a counter so we can simply increment inside parentheses.
unsigned GtIsGt = 1;
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
}
void printClose(char Close = ')') {
GtIsGt--;
*this += Close;
}
OutputBuffer &operator+=(StringView R) {
if (size_t Size = R.size()) {
grow(Size);
std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
}
return *this;
}
OutputBuffer &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputBuffer &prepend(StringView R) {
size_t Size = R.size();
grow(Size);
std::memmove(Buffer + Size, Buffer, CurrentPosition);
std::memcpy(Buffer, R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputBuffer &operator<<(StringView R) { return (*this += R); }
OutputBuffer &operator<<(char C) { return (*this += C); }
OutputBuffer &operator<<(long long N) {
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
}
OutputBuffer &operator<<(unsigned long long N) {
return writeUnsigned(N, false);
}
OutputBuffer &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputBuffer &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputBuffer &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputBuffer &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
if (N == 0)
return;
grow(N);
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
std::memcpy(Buffer + Pos, S, N);
CurrentPosition += N;
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
assert(CurrentPosition);
return Buffer[CurrentPosition - 1];
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class ScopedOverride {
T &Loc;
T Original;
public:
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
Loc_ = std::move(NewVal);
}
~ScopedOverride() { Loc = std::move(Original); }
ScopedOverride(const ScopedOverride &) = delete;
ScopedOverride &operator=(const ScopedOverride &) = delete;
};
inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
OB.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -0,0 +1,578 @@
//===--- DLangDemangle.cpp ------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines a demangler for the D programming language as specified
/// in the ABI specification, available at:
/// https://dlang.org/spec/abi.html#name_mangling
///
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
#include <cctype>
#include <cstring>
#include <limits>
using namespace llvm;
using llvm::itanium_demangle::OutputBuffer;
using llvm::itanium_demangle::StringView;
namespace {
/// Demangle information structure.
struct Demangler {
/// Initialize the information structure we use to pass around information.
///
/// \param Mangled String to demangle.
Demangler(const char *Mangled);
/// Extract and demangle the mangled symbol and append it to the output
/// string.
///
/// \param Demangled Output buffer to write the demangled name.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#name_mangling .
/// \see https://dlang.org/spec/abi.html#MangledName .
const char *parseMangle(OutputBuffer *Demangled);
private:
/// Extract and demangle a given mangled symbol and append it to the output
/// string.
///
/// \param Demangled output buffer to write the demangled name.
/// \param Mangled mangled symbol to be demangled.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#name_mangling .
/// \see https://dlang.org/spec/abi.html#MangledName .
const char *parseMangle(OutputBuffer *Demangled, const char *Mangled);
/// Extract the number from a given string.
///
/// \param Mangled string to extract the number.
/// \param Ret assigned result value.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \note A result larger than UINT_MAX is considered a failure.
///
/// \see https://dlang.org/spec/abi.html#Number .
const char *decodeNumber(const char *Mangled, unsigned long &Ret);
/// Extract the back reference position from a given string.
///
/// \param Mangled string to extract the back reference position.
/// \param Ret assigned result value.
///
/// \return the remaining string on success or nullptr on failure.
///
/// \note Ret is always >= 0 on success, and unspecified on failure
///
/// \see https://dlang.org/spec/abi.html#back_ref .
/// \see https://dlang.org/spec/abi.html#NumberBackRef .
const char *decodeBackrefPos(const char *Mangled, long &Ret);
/// Extract the symbol pointed by the back reference form a given string.
///
/// \param Mangled string to extract the back reference position.
/// \param Ret assigned result value.
///
/// \return the remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#back_ref .
const char *decodeBackref(const char *Mangled, const char *&Ret);
/// Extract and demangle backreferenced symbol from a given mangled symbol
/// and append it to the output string.
///
/// \param Demangled output buffer to write the demangled name.
/// \param Mangled mangled symbol to be demangled.
///
/// \return the remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#back_ref .
/// \see https://dlang.org/spec/abi.html#IdentifierBackRef .
const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled);
/// Extract and demangle backreferenced type from a given mangled symbol
/// and append it to the output string.
///
/// \param Mangled mangled symbol to be demangled.
///
/// \return the remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#back_ref .
/// \see https://dlang.org/spec/abi.html#TypeBackRef .
const char *parseTypeBackref(const char *Mangled);
/// Check whether it is the beginning of a symbol name.
///
/// \param Mangled string to extract the symbol name.
///
/// \return true on success, false otherwise.
///
/// \see https://dlang.org/spec/abi.html#SymbolName .
bool isSymbolName(const char *Mangled);
/// Extract and demangle an identifier from a given mangled symbol append it
/// to the output string.
///
/// \param Demangled Output buffer to write the demangled name.
/// \param Mangled Mangled symbol to be demangled.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#SymbolName .
const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled);
/// Extract and demangle the plain identifier from a given mangled symbol and
/// prepend/append it to the output string, with a special treatment for some
/// magic compiler generated symbols.
///
/// \param Demangled Output buffer to write the demangled name.
/// \param Mangled Mangled symbol to be demangled.
/// \param Len Length of the mangled symbol name.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#LName .
const char *parseLName(OutputBuffer *Demangled, const char *Mangled,
unsigned long Len);
/// Extract and demangle the qualified symbol from a given mangled symbol
/// append it to the output string.
///
/// \param Demangled Output buffer to write the demangled name.
/// \param Mangled Mangled symbol to be demangled.
///
/// \return The remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#QualifiedName .
const char *parseQualified(OutputBuffer *Demangled, const char *Mangled);
/// Extract and demangle a type from a given mangled symbol append it to
/// the output string.
///
/// \param Mangled mangled symbol to be demangled.
///
/// \return the remaining string on success or nullptr on failure.
///
/// \see https://dlang.org/spec/abi.html#Type .
const char *parseType(const char *Mangled);
/// The string we are demangling.
const char *Str;
/// The index of the last back reference.
int LastBackref;
};
} // namespace
const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) {
// Return nullptr if trying to extract something that isn't a digit.
if (Mangled == nullptr || !std::isdigit(*Mangled))
return nullptr;
unsigned long Val = 0;
do {
unsigned long Digit = Mangled[0] - '0';
// Check for overflow.
if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10)
return nullptr;
Val = Val * 10 + Digit;
++Mangled;
} while (std::isdigit(*Mangled));
if (*Mangled == '\0')
return nullptr;
Ret = Val;
return Mangled;
}
const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) {
// Return nullptr if trying to extract something that isn't a digit
if (Mangled == nullptr || !std::isalpha(*Mangled))
return nullptr;
// Any identifier or non-basic type that has been emitted to the mangled
// symbol before will not be emitted again, but is referenced by a special
// sequence encoding the relative position of the original occurrence in the
// mangled symbol name.
// Numbers in back references are encoded with base 26 by upper case letters
// A-Z for higher digits but lower case letters a-z for the last digit.
// NumberBackRef:
// [a-z]
// [A-Z] NumberBackRef
// ^
unsigned long Val = 0;
while (std::isalpha(*Mangled)) {
// Check for overflow
if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26)
break;
Val *= 26;
if (Mangled[0] >= 'a' && Mangled[0] <= 'z') {
Val += Mangled[0] - 'a';
if ((long)Val <= 0)
break;
Ret = Val;
return Mangled + 1;
}
Val += Mangled[0] - 'A';
++Mangled;
}
return nullptr;
}
const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) {
assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!");
Ret = nullptr;
// Position of 'Q'
const char *Qpos = Mangled;
long RefPos;
++Mangled;
Mangled = decodeBackrefPos(Mangled, RefPos);
if (Mangled == nullptr)
return nullptr;
if (RefPos > Qpos - Str)
return nullptr;
// Set the position of the back reference.
Ret = Qpos - RefPos;
return Mangled;
}
const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled,
const char *Mangled) {
// An identifier back reference always points to a digit 0 to 9.
// IdentifierBackRef:
// Q NumberBackRef
// ^
const char *Backref;
unsigned long Len;
// Get position of the back reference
Mangled = decodeBackref(Mangled, Backref);
// Must point to a simple identifier
Backref = decodeNumber(Backref, Len);
if (Backref == nullptr || strlen(Backref) < Len)
return nullptr;
Backref = parseLName(Demangled, Backref, Len);
if (Backref == nullptr)
return nullptr;
return Mangled;
}
const char *Demangler::parseTypeBackref(const char *Mangled) {
// A type back reference always points to a letter.
// TypeBackRef:
// Q NumberBackRef
// ^
const char *Backref;
// If we appear to be moving backwards through the mangle string, then
// bail as this may be a recursive back reference.
if (Mangled - Str >= LastBackref)
return nullptr;
int SaveRefPos = LastBackref;
LastBackref = Mangled - Str;
// Get position of the back reference.
Mangled = decodeBackref(Mangled, Backref);
// Can't decode back reference.
if (Backref == nullptr)
return nullptr;
// TODO: Add support for function type back references.
Backref = parseType(Backref);
LastBackref = SaveRefPos;
if (Backref == nullptr)
return nullptr;
return Mangled;
}
bool Demangler::isSymbolName(const char *Mangled) {
long Ret;
const char *Qref = Mangled;
if (std::isdigit(*Mangled))
return true;
// TODO: Handle template instances.
if (*Mangled != 'Q')
return false;
Mangled = decodeBackrefPos(Mangled + 1, Ret);
if (Mangled == nullptr || Ret > Qref - Str)
return false;
return std::isdigit(Qref[-Ret]);
}
const char *Demangler::parseMangle(OutputBuffer *Demangled,
const char *Mangled) {
// A D mangled symbol is comprised of both scope and type information.
// MangleName:
// _D QualifiedName Type
// _D QualifiedName Z
// ^
// The caller should have guaranteed that the start pointer is at the
// above location.
// Note that type is never a function type, but only the return type of
// a function or the type of a variable.
Mangled += 2;
Mangled = parseQualified(Demangled, Mangled);
if (Mangled != nullptr) {
// Artificial symbols end with 'Z' and have no type.
if (*Mangled == 'Z')
++Mangled;
else {
Mangled = parseType(Mangled);
}
}
return Mangled;
}
const char *Demangler::parseQualified(OutputBuffer *Demangled,
const char *Mangled) {
// Qualified names are identifiers separated by their encoded length.
// Nested functions also encode their argument types without specifying
// what they return.
// QualifiedName:
// SymbolFunctionName
// SymbolFunctionName QualifiedName
// ^
// SymbolFunctionName:
// SymbolName
// SymbolName TypeFunctionNoReturn
// SymbolName M TypeFunctionNoReturn
// SymbolName M TypeModifiers TypeFunctionNoReturn
// The start pointer should be at the above location.
// Whether it has more than one symbol
size_t NotFirst = false;
do {
// Skip over anonymous symbols.
if (*Mangled == '0') {
do
++Mangled;
while (*Mangled == '0');
continue;
}
if (NotFirst)
*Demangled << '.';
NotFirst = true;
Mangled = parseIdentifier(Demangled, Mangled);
} while (Mangled && isSymbolName(Mangled));
return Mangled;
}
const char *Demangler::parseIdentifier(OutputBuffer *Demangled,
const char *Mangled) {
unsigned long Len;
if (Mangled == nullptr || *Mangled == '\0')
return nullptr;
if (*Mangled == 'Q')
return parseSymbolBackref(Demangled, Mangled);
// TODO: Parse lengthless template instances.
const char *Endptr = decodeNumber(Mangled, Len);
if (Endptr == nullptr || Len == 0)
return nullptr;
if (strlen(Endptr) < Len)
return nullptr;
Mangled = Endptr;
// TODO: Parse template instances with a length prefix.
// There can be multiple different declarations in the same function that
// have the same mangled name. To make the mangled names unique, a fake
// parent in the form `__Sddd' is added to the symbol.
if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') {
const char *NumPtr = Mangled + 3;
while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr))
++NumPtr;
if (Mangled + Len == NumPtr) {
// Skip over the fake parent.
Mangled += Len;
return parseIdentifier(Demangled, Mangled);
}
// Else demangle it as a plain identifier.
}
return parseLName(Demangled, Mangled, Len);
}
const char *Demangler::parseType(const char *Mangled) {
if (*Mangled == '\0')
return nullptr;
switch (*Mangled) {
// TODO: Parse type qualifiers.
// TODO: Parse function types.
// TODO: Parse compound types.
// TODO: Parse delegate types.
// TODO: Parse tuple types.
// Basic types.
case 'i':
++Mangled;
// TODO: Add type name dumping
return Mangled;
// TODO: Add support for the rest of the basic types.
// Back referenced type.
case 'Q':
return parseTypeBackref(Mangled);
default: // unhandled.
return nullptr;
}
}
const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled,
unsigned long Len) {
switch (Len) {
case 6:
if (strncmp(Mangled, "__initZ", Len + 1) == 0) {
// The static initializer for a given symbol.
Demangled->prepend("initializer for ");
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
Mangled += Len;
return Mangled;
}
if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) {
// The vtable symbol for a given class.
Demangled->prepend("vtable for ");
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
Mangled += Len;
return Mangled;
}
break;
case 7:
if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) {
// The classinfo symbol for a given class.
Demangled->prepend("ClassInfo for ");
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
Mangled += Len;
return Mangled;
}
break;
case 11:
if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) {
// The interface symbol for a given class.
Demangled->prepend("Interface for ");
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
Mangled += Len;
return Mangled;
}
break;
case 12:
if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) {
// The ModuleInfo symbol for a given module.
Demangled->prepend("ModuleInfo for ");
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
Mangled += Len;
return Mangled;
}
break;
}
*Demangled << StringView(Mangled, Len);
Mangled += Len;
return Mangled;
}
Demangler::Demangler(const char *Mangled)
: Str(Mangled), LastBackref(strlen(Mangled)) {}
const char *Demangler::parseMangle(OutputBuffer *Demangled) {
return parseMangle(Demangled, this->Str);
}
char *llvm::dlangDemangle(const char *MangledName) {
if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0)
return nullptr;
OutputBuffer Demangled;
if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024))
return nullptr;
if (strcmp(MangledName, "_Dmain") == 0) {
Demangled << "D main";
} else {
Demangler D = Demangler(MangledName);
MangledName = D.parseMangle(&Demangled);
// Check that the entire symbol was successfully demangled.
if (MangledName == nullptr || *MangledName != '\0') {
std::free(Demangled.getBuffer());
return nullptr;
}
}
// OutputBuffer's internal buffer is not null terminated and therefore we need
// to add it to comply with C null terminated strings.
if (Demangled.getCurrentPosition() > 0) {
Demangled << '\0';
Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1);
return Demangled.getBuffer();
}
std::free(Demangled.getBuffer());
return nullptr;
}

View File

@ -0,0 +1,64 @@
//===-- Demangle.cpp - Common demangling functions ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file This file contains definitions of common demangling functions.
///
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
#include <cstdlib>
#include <cstring>
static bool isItaniumEncoding(const char *S) {
// Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0;
}
static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; }
static bool isDLangEncoding(const std::string &MangledName) {
return MangledName.size() >= 2 && MangledName[0] == '_' &&
MangledName[1] == 'D';
}
std::string llvm::demangle(const std::string &MangledName) {
std::string Result;
const char *S = MangledName.c_str();
if (nonMicrosoftDemangle(S, Result))
return Result;
if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result))
return Result;
if (char *Demangled =
microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) {
Result = Demangled;
std::free(Demangled);
return Result;
}
return MangledName;
}
bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) {
char *Demangled = nullptr;
if (isItaniumEncoding(MangledName))
Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr);
else if (isRustEncoding(MangledName))
Demangled = rustDemangle(MangledName);
else if (isDLangEncoding(MangledName))
Demangled = dlangDemangle(MangledName);
if (!Demangled)
return false;
Result = Demangled;
std::free(Demangled);
return true;
}

View File

@ -19,9 +19,7 @@
#include <cstdlib>
#include <cstring>
#include <functional>
#include <numeric>
#include <utility>
#include <vector>
using namespace llvm;
using namespace llvm::itanium_demangle;
@ -174,6 +172,50 @@ struct DumpVisitor {
return printStr("TemplateParamKind::Template");
}
}
void print(Node::Prec P) {
switch (P) {
case Node::Prec::Primary:
return printStr("Node::Prec::Primary");
case Node::Prec::Postfix:
return printStr("Node::Prec::Postfix");
case Node::Prec::Unary:
return printStr("Node::Prec::Unary");
case Node::Prec::Cast:
return printStr("Node::Prec::Cast");
case Node::Prec::PtrMem:
return printStr("Node::Prec::PtrMem");
case Node::Prec::Multiplicative:
return printStr("Node::Prec::Multiplicative");
case Node::Prec::Additive:
return printStr("Node::Prec::Additive");
case Node::Prec::Shift:
return printStr("Node::Prec::Shift");
case Node::Prec::Spaceship:
return printStr("Node::Prec::Spaceship");
case Node::Prec::Relational:
return printStr("Node::Prec::Relational");
case Node::Prec::Equality:
return printStr("Node::Prec::Equality");
case Node::Prec::And:
return printStr("Node::Prec::And");
case Node::Prec::Xor:
return printStr("Node::Prec::Xor");
case Node::Prec::Ior:
return printStr("Node::Prec::Ior");
case Node::Prec::AndIf:
return printStr("Node::Prec::AndIf");
case Node::Prec::OrIf:
return printStr("Node::Prec::OrIf");
case Node::Prec::Conditional:
return printStr("Node::Prec::Conditional");
case Node::Prec::Assign:
return printStr("Node::Prec::Assign");
case Node::Prec::Comma:
return printStr("Node::Prec::Comma");
case Node::Prec::Default:
return printStr("Node::Prec::Default");
}
}
void newLine() {
printStr("\n");
@ -333,21 +375,21 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
OutputStream S;
OutputBuffer OB;
Node *AST = Parser.parse();
if (AST == nullptr)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))
else if (!initializeOutputBuffer(Buf, N, OB, 1024))
InternalStatus = demangle_memory_alloc_failure;
else {
assert(Parser.ForwardTemplateRefs.empty());
AST->print(S);
S += '\0';
AST->print(OB);
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
*N = OB.getCurrentPosition();
Buf = OB.getBuffer();
}
if (Status)
@ -385,14 +427,14 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
}
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
OutputBuffer OB;
if (!initializeOutputBuffer(Buf, N, OB, 128))
return nullptr;
RootNode->print(S);
S += '\0';
RootNode->print(OB);
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
@ -406,8 +448,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
case Node::KAbiTagAttr:
Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue;
case Node::KStdQualifiedName:
Name = static_cast<const StdQualifiedName *>(Name)->Child;
case Node::KModuleEntity:
Name = static_cast<const ModuleEntity *>(Name)->Name;
continue;
case Node::KNestedName:
Name = static_cast<const NestedName *>(Name)->Name;
@ -430,8 +472,8 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
OutputBuffer OB;
if (!initializeOutputBuffer(Buf, N, OB, 128))
return nullptr;
KeepGoingLocalFunction:
@ -447,27 +489,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
break;
}
if (Name->getKind() == Node::KModuleEntity)
Name = static_cast<const ModuleEntity *>(Name)->Name;
switch (Name->getKind()) {
case Node::KStdQualifiedName:
S += "std";
break;
case Node::KNestedName:
static_cast<const NestedName *>(Name)->Qual->print(S);
static_cast<const NestedName *>(Name)->Qual->print(OB);
break;
case Node::KLocalName: {
auto *LN = static_cast<const LocalName *>(Name);
LN->Encoding->print(S);
S += "::";
LN->Encoding->print(OB);
OB += "::";
Name = LN->Entity;
goto KeepGoingLocalFunction;
}
default:
break;
}
S += '\0';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
@ -483,17 +525,17 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
return nullptr;
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
OutputBuffer OB;
if (!initializeOutputBuffer(Buf, N, OB, 128))
return nullptr;
S += '(';
Params.printWithComma(S);
S += ')';
S += '\0';
OB += '(';
Params.printWithComma(OB);
OB += ')';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::getFunctionReturnType(
@ -501,18 +543,18 @@ char *ItaniumPartialDemangler::getFunctionReturnType(
if (!isFunction())
return nullptr;
OutputStream S;
if (!initializeOutputStream(Buf, N, S, 128))
OutputBuffer OB;
if (!initializeOutputBuffer(Buf, N, OB, 128))
return nullptr;
if (const Node *Ret =
static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
Ret->print(S);
Ret->print(OB);
S += '\0';
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
return S.getBuffer();
*N = OB.getCurrentPosition();
return OB.getBuffer();
}
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
@ -552,8 +594,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
case Node::KNestedName:
N = static_cast<const NestedName *>(N)->Name;
break;
case Node::KStdQualifiedName:
N = static_cast<const StdQualifiedName *>(N)->Child;
case Node::KModuleEntity:
N = static_cast<const ModuleEntity *>(N)->Name;
break;
}
}

View File

@ -245,8 +245,8 @@ demanglePointerCVQualifiers(StringView &MangledName) {
}
StringView Demangler::copyString(StringView Borrowed) {
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);
std::strcpy(Stable, Borrowed.begin());
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
std::memcpy(Stable, Borrowed.begin(), Borrowed.size());
return {Stable, Borrowed.size()};
}
@ -823,11 +823,15 @@ SymbolNode *Demangler::parse(StringView &MangledName) {
}
TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
if (!MangledName.consumeFront(".?A"))
if (!MangledName.consumeFront(".?A")) {
Error = true;
return nullptr;
}
MangledName.consumeFront(".?A");
if (MangledName.empty())
if (MangledName.empty()) {
Error = true;
return nullptr;
}
return demangleClassType(MangledName);
}
@ -965,17 +969,14 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {
void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
// Render this class template name into a string buffer so that we can
// memorize it for the purpose of back-referencing.
OutputStream OS;
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
OutputBuffer OB;
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
// FIXME: Propagate out-of-memory as an error?
std::terminate();
Identifier->output(OS, OF_Default);
OS << '\0';
char *Name = OS.getBuffer();
StringView Owned = copyString(Name);
Identifier->output(OB, OF_Default);
StringView Owned = copyString(OB);
memorizeString(Owned);
std::free(Name);
std::free(OB.getBuffer());
}
IdentifierNode *
@ -1107,7 +1108,7 @@ static void writeHexDigit(char *Buffer, uint8_t Digit) {
*Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);
}
static void outputHex(OutputStream &OS, unsigned C) {
static void outputHex(OutputBuffer &OB, unsigned C) {
assert (C != 0);
// It's easier to do the math if we can work from right to left, but we need
@ -1130,43 +1131,43 @@ static void outputHex(OutputStream &OS, unsigned C) {
TempBuffer[Pos--] = 'x';
assert(Pos >= 0);
TempBuffer[Pos--] = '\\';
OS << StringView(&TempBuffer[Pos + 1]);
OB << StringView(&TempBuffer[Pos + 1]);
}
static void outputEscapedChar(OutputStream &OS, unsigned C) {
static void outputEscapedChar(OutputBuffer &OB, unsigned C) {
switch (C) {
case '\0': // nul
OS << "\\0";
OB << "\\0";
return;
case '\'': // single quote
OS << "\\\'";
OB << "\\\'";
return;
case '\"': // double quote
OS << "\\\"";
OB << "\\\"";
return;
case '\\': // backslash
OS << "\\\\";
OB << "\\\\";
return;
case '\a': // bell
OS << "\\a";
OB << "\\a";
return;
case '\b': // backspace
OS << "\\b";
OB << "\\b";
return;
case '\f': // form feed
OS << "\\f";
OB << "\\f";
return;
case '\n': // new line
OS << "\\n";
OB << "\\n";
return;
case '\r': // carriage return
OS << "\\r";
OB << "\\r";
return;
case '\t': // tab
OS << "\\t";
OB << "\\t";
return;
case '\v': // vertical tab
OS << "\\v";
OB << "\\v";
return;
default:
break;
@ -1174,11 +1175,11 @@ static void outputEscapedChar(OutputStream &OS, unsigned C) {
if (C > 0x1F && C < 0x7F) {
// Standard ascii char.
OS << (char)C;
OB << (char)C;
return;
}
outputHex(OS, C);
outputHex(OB, C);
}
static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
@ -1273,18 +1274,17 @@ FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {
EncodedStringLiteralNode *
Demangler::demangleStringLiteral(StringView &MangledName) {
// This function uses goto, so declare all variables up front.
OutputStream OS;
OutputBuffer OB;
StringView CRC;
uint64_t StringByteSize;
bool IsWcharT = false;
bool IsNegative = false;
size_t CrcEndPos = 0;
char *ResultBuffer = nullptr;
EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
// Must happen before the first `goto StringLiteralError`.
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
// FIXME: Propagate out-of-memory as an error?
std::terminate();
@ -1329,7 +1329,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
goto StringLiteralError;
wchar_t W = demangleWcharLiteral(MangledName);
if (StringByteSize != 2 || Result->IsTruncated)
outputEscapedChar(OS, W);
outputEscapedChar(OB, W);
StringByteSize -= 2;
if (Error)
goto StringLiteralError;
@ -1371,19 +1371,17 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
unsigned NextChar =
decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
if (CharIndex + 1 < NumChars || Result->IsTruncated)
outputEscapedChar(OS, NextChar);
outputEscapedChar(OB, NextChar);
}
}
OS << '\0';
ResultBuffer = OS.getBuffer();
Result->DecodedString = copyString(ResultBuffer);
std::free(ResultBuffer);
Result->DecodedString = copyString(OB);
std::free(OB.getBuffer());
return Result;
StringLiteralError:
Error = true;
std::free(OS.getBuffer());
std::free(OB.getBuffer());
return nullptr;
}
@ -1447,18 +1445,17 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
return nullptr;
// Render the parent symbol's name into a buffer.
OutputStream OS;
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
OutputBuffer OB;
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
// FIXME: Propagate out-of-memory as an error?
std::terminate();
OS << '`';
Scope->output(OS, OF_Default);
OS << '\'';
OS << "::`" << Number << "'";
OS << '\0';
char *Result = OS.getBuffer();
Identifier->Name = copyString(Result);
std::free(Result);
OB << '`';
Scope->output(OB, OF_Default);
OB << '\'';
OB << "::`" << Number << "'";
Identifier->Name = copyString(OB);
std::free(OB.getBuffer());
return Identifier;
}
@ -1711,6 +1708,10 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
return CallingConv::Eabi;
case 'Q':
return CallingConv::Vectorcall;
case 'S':
return CallingConv::Swift;
case 'W':
return CallingConv::SwiftAsync;
}
return CallingConv::None;
@ -2309,19 +2310,19 @@ void Demangler::dumpBackReferences() {
(int)Backrefs.FunctionParamCount);
// Create an output stream so we can render each type.
OutputStream OS;
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
OutputBuffer OB;
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
std::terminate();
for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
OS.setCurrentPosition(0);
OB.setCurrentPosition(0);
TypeNode *T = Backrefs.FunctionParams[I];
T->output(OS, OF_Default);
T->output(OB, OF_Default);
std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(),
OS.getBuffer());
StringView B = OB;
std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin());
}
std::free(OS.getBuffer());
std::free(OB.getBuffer());
if (Backrefs.FunctionParamCount > 0)
std::printf("\n");
@ -2338,7 +2339,7 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
char *Buf, size_t *N,
int *Status, MSDemangleFlags Flags) {
Demangler D;
OutputStream S;
OutputBuffer OB;
StringView Name{MangledName};
SymbolNode *AST = D.parse(Name);
@ -2357,18 +2358,20 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
OF = OutputFlags(OF | OF_NoReturnType);
if (Flags & MSDF_NoMemberType)
OF = OutputFlags(OF | OF_NoMemberType);
if (Flags & MSDF_NoVariableType)
OF = OutputFlags(OF | OF_NoVariableType);
int InternalStatus = demangle_success;
if (D.Error)
InternalStatus = demangle_invalid_mangled_name;
else if (!initializeOutputStream(Buf, N, S, 1024))
else if (!initializeOutputBuffer(Buf, N, OB, 1024))
InternalStatus = demangle_memory_alloc_failure;
else {
AST->output(S, OF);
S += '\0';
AST->output(OB, OF);
OB += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
*N = OB.getCurrentPosition();
Buf = OB.getBuffer();
}
if (Status)

View File

@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
#include "llvm/Demangle/DemangleConfig.h"
#include "llvm/Demangle/Utility.h"
#include <cctype>
#include <string>
@ -21,91 +20,97 @@ using namespace ms_demangle;
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
case Enum::Value: \
OS << Desc; \
OB << Desc; \
break;
// Writes a space if the last token does not end with a punctuation.
static void outputSpaceIfNecessary(OutputStream &OS) {
if (OS.empty())
static void outputSpaceIfNecessary(OutputBuffer &OB) {
if (OB.empty())
return;
char C = OS.back();
char C = OB.back();
if (std::isalnum(C) || C == '>')
OS << " ";
OB << " ";
}
static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) {
switch (Q) {
case Q_Const:
OS << "const";
OB << "const";
break;
case Q_Volatile:
OS << "volatile";
OB << "volatile";
break;
case Q_Restrict:
OS << "__restrict";
OB << "__restrict";
break;
default:
break;
}
}
static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q,
Qualifiers Mask, bool NeedSpace) {
if (!(Q & Mask))
return NeedSpace;
if (NeedSpace)
OS << " ";
OB << " ";
outputSingleQualifier(OS, Mask);
outputSingleQualifier(OB, Mask);
return true;
}
static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
bool SpaceAfter) {
if (Q == Q_None)
return;
size_t Pos1 = OS.getCurrentPosition();
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
size_t Pos2 = OS.getCurrentPosition();
size_t Pos1 = OB.getCurrentPosition();
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
size_t Pos2 = OB.getCurrentPosition();
if (SpaceAfter && Pos2 > Pos1)
OS << " ";
OB << " ";
}
static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
outputSpaceIfNecessary(OS);
static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) {
outputSpaceIfNecessary(OB);
switch (CC) {
case CallingConv::Cdecl:
OS << "__cdecl";
OB << "__cdecl";
break;
case CallingConv::Fastcall:
OS << "__fastcall";
OB << "__fastcall";
break;
case CallingConv::Pascal:
OS << "__pascal";
OB << "__pascal";
break;
case CallingConv::Regcall:
OS << "__regcall";
OB << "__regcall";
break;
case CallingConv::Stdcall:
OS << "__stdcall";
OB << "__stdcall";
break;
case CallingConv::Thiscall:
OS << "__thiscall";
OB << "__thiscall";
break;
case CallingConv::Eabi:
OS << "__eabi";
OB << "__eabi";
break;
case CallingConv::Vectorcall:
OS << "__vectorcall";
OB << "__vectorcall";
break;
case CallingConv::Clrcall:
OS << "__clrcall";
OB << "__clrcall";
break;
case CallingConv::Swift:
OB << "__attribute__((__swiftcall__)) ";
break;
case CallingConv::SwiftAsync:
OB << "__attribute__((__swiftasynccall__)) ";
break;
default:
break;
@ -113,14 +118,16 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
}
std::string Node::toString(OutputFlags Flags) const {
OutputStream OS;
initializeOutputStream(nullptr, nullptr, OS, 1024);
this->output(OS, Flags);
OS << '\0';
return {OS.getBuffer()};
OutputBuffer OB;
initializeOutputBuffer(nullptr, nullptr, OB, 1024);
this->output(OB, Flags);
StringView SV = OB;
std::string Owned(SV.begin(), SV.end());
std::free(OB.getBuffer());
return Owned;
}
void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
switch (PrimKind) {
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
@ -144,107 +151,107 @@ void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
}
outputQualifiers(OS, Quals, true, false);
outputQualifiers(OB, Quals, true, false);
}
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
output(OS, Flags, ", ");
void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const {
output(OB, Flags, ", ");
}
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags,
StringView Separator) const {
if (Count == 0)
return;
if (Nodes[0])
Nodes[0]->output(OS, Flags);
Nodes[0]->output(OB, Flags);
for (size_t I = 1; I < Count; ++I) {
OS << Separator;
Nodes[I]->output(OS, Flags);
OB << Separator;
Nodes[I]->output(OB, Flags);
}
}
void EncodedStringLiteralNode::output(OutputStream &OS,
void EncodedStringLiteralNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
switch (Char) {
case CharKind::Wchar:
OS << "L\"";
OB << "L\"";
break;
case CharKind::Char:
OS << "\"";
OB << "\"";
break;
case CharKind::Char16:
OS << "u\"";
OB << "u\"";
break;
case CharKind::Char32:
OS << "U\"";
OB << "U\"";
break;
}
OS << DecodedString << "\"";
OB << DecodedString << "\"";
if (IsTruncated)
OS << "...";
OB << "...";
}
void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const {
if (IsNegative)
OS << '-';
OS << Value;
OB << '-';
OB << Value;
}
void TemplateParameterReferenceNode::output(OutputStream &OS,
void TemplateParameterReferenceNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
if (ThunkOffsetCount > 0)
OS << "{";
OB << "{";
else if (Affinity == PointerAffinity::Pointer)
OS << "&";
OB << "&";
if (Symbol) {
Symbol->output(OS, Flags);
Symbol->output(OB, Flags);
if (ThunkOffsetCount > 0)
OS << ", ";
OB << ", ";
}
if (ThunkOffsetCount > 0)
OS << ThunkOffsets[0];
OB << ThunkOffsets[0];
for (int I = 1; I < ThunkOffsetCount; ++I) {
OS << ", " << ThunkOffsets[I];
OB << ", " << ThunkOffsets[I];
}
if (ThunkOffsetCount > 0)
OS << "}";
OB << "}";
}
void IdentifierNode::outputTemplateParameters(OutputStream &OS,
void IdentifierNode::outputTemplateParameters(OutputBuffer &OB,
OutputFlags Flags) const {
if (!TemplateParams)
return;
OS << "<";
TemplateParams->output(OS, Flags);
OS << ">";
OB << "<";
TemplateParams->output(OB, Flags);
OB << ">";
}
void DynamicStructorIdentifierNode::output(OutputStream &OS,
void DynamicStructorIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
if (IsDestructor)
OS << "`dynamic atexit destructor for ";
OB << "`dynamic atexit destructor for ";
else
OS << "`dynamic initializer for ";
OB << "`dynamic initializer for ";
if (Variable) {
OS << "`";
Variable->output(OS, Flags);
OS << "''";
OB << "`";
Variable->output(OB, Flags);
OB << "''";
} else {
OS << "'";
Name->output(OS, Flags);
OS << "''";
OB << "'";
Name->output(OB, Flags);
OB << "''";
}
}
void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
OS << Name;
outputTemplateParameters(OS, Flags);
void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
OB << Name;
outputTemplateParameters(OB, Flags);
}
void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
switch (Operator) {
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
@ -342,188 +349,188 @@ void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
case IntrinsicFunctionKind::None:
break;
}
outputTemplateParameters(OS, Flags);
outputTemplateParameters(OB, Flags);
}
void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
if (IsThread)
OS << "`local static thread guard'";
OB << "`local static thread guard'";
else
OS << "`local static guard'";
OB << "`local static guard'";
if (ScopeIndex > 0)
OS << "{" << ScopeIndex << "}";
OB << "{" << ScopeIndex << "}";
}
void ConversionOperatorIdentifierNode::output(OutputStream &OS,
void ConversionOperatorIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
OS << "operator";
outputTemplateParameters(OS, Flags);
OS << " ";
TargetType->output(OS, Flags);
OB << "operator";
outputTemplateParameters(OB, Flags);
OB << " ";
TargetType->output(OB, Flags);
}
void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
if (IsDestructor)
OS << "~";
Class->output(OS, Flags);
outputTemplateParameters(OS, Flags);
OB << "~";
Class->output(OB, Flags);
outputTemplateParameters(OB, Flags);
}
void LiteralOperatorIdentifierNode::output(OutputStream &OS,
void LiteralOperatorIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
OS << "operator \"\"" << Name;
outputTemplateParameters(OS, Flags);
OB << "operator \"\"" << Name;
outputTemplateParameters(OB, Flags);
}
void FunctionSignatureNode::outputPre(OutputStream &OS,
void FunctionSignatureNode::outputPre(OutputBuffer &OB,
OutputFlags Flags) const {
if (!(Flags & OF_NoAccessSpecifier)) {
if (FunctionClass & FC_Public)
OS << "public: ";
OB << "public: ";
if (FunctionClass & FC_Protected)
OS << "protected: ";
OB << "protected: ";
if (FunctionClass & FC_Private)
OS << "private: ";
OB << "private: ";
}
if (!(Flags & OF_NoMemberType)) {
if (!(FunctionClass & FC_Global)) {
if (FunctionClass & FC_Static)
OS << "static ";
OB << "static ";
}
if (FunctionClass & FC_Virtual)
OS << "virtual ";
OB << "virtual ";
if (FunctionClass & FC_ExternC)
OS << "extern \"C\" ";
OB << "extern \"C\" ";
}
if (!(Flags & OF_NoReturnType) && ReturnType) {
ReturnType->outputPre(OS, Flags);
OS << " ";
ReturnType->outputPre(OB, Flags);
OB << " ";
}
if (!(Flags & OF_NoCallingConvention))
outputCallingConvention(OS, CallConvention);
outputCallingConvention(OB, CallConvention);
}
void FunctionSignatureNode::outputPost(OutputStream &OS,
void FunctionSignatureNode::outputPost(OutputBuffer &OB,
OutputFlags Flags) const {
if (!(FunctionClass & FC_NoParameterList)) {
OS << "(";
OB << "(";
if (Params)
Params->output(OS, Flags);
Params->output(OB, Flags);
else
OS << "void";
OB << "void";
if (IsVariadic) {
if (OS.back() != '(')
OS << ", ";
OS << "...";
if (OB.back() != '(')
OB << ", ";
OB << "...";
}
OS << ")";
OB << ")";
}
if (Quals & Q_Const)
OS << " const";
OB << " const";
if (Quals & Q_Volatile)
OS << " volatile";
OB << " volatile";
if (Quals & Q_Restrict)
OS << " __restrict";
OB << " __restrict";
if (Quals & Q_Unaligned)
OS << " __unaligned";
OB << " __unaligned";
if (IsNoexcept)
OS << " noexcept";
OB << " noexcept";
if (RefQualifier == FunctionRefQualifier::Reference)
OS << " &";
OB << " &";
else if (RefQualifier == FunctionRefQualifier::RValueReference)
OS << " &&";
OB << " &&";
if (!(Flags & OF_NoReturnType) && ReturnType)
ReturnType->outputPost(OS, Flags);
ReturnType->outputPost(OB, Flags);
}
void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
OS << "[thunk]: ";
void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
OB << "[thunk]: ";
FunctionSignatureNode::outputPre(OS, Flags);
FunctionSignatureNode::outputPre(OB, Flags);
}
void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
if (FunctionClass & FC_StaticThisAdjust) {
OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
} else if (FunctionClass & FC_VirtualThisAdjust) {
if (FunctionClass & FC_VirtualThisAdjustEx) {
OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
<< ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
<< ", " << ThisAdjust.StaticOffset << "}'";
} else {
OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
<< ThisAdjust.StaticOffset << "}'";
}
}
FunctionSignatureNode::outputPost(OS, Flags);
FunctionSignatureNode::outputPost(OB, Flags);
}
void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
if (Pointee->kind() == NodeKind::FunctionSignature) {
// If this is a pointer to a function, don't output the calling convention.
// It needs to go inside the parentheses.
const FunctionSignatureNode *Sig =
static_cast<const FunctionSignatureNode *>(Pointee);
Sig->outputPre(OS, OF_NoCallingConvention);
Sig->outputPre(OB, OF_NoCallingConvention);
} else
Pointee->outputPre(OS, Flags);
Pointee->outputPre(OB, Flags);
outputSpaceIfNecessary(OS);
outputSpaceIfNecessary(OB);
if (Quals & Q_Unaligned)
OS << "__unaligned ";
OB << "__unaligned ";
if (Pointee->kind() == NodeKind::ArrayType) {
OS << "(";
OB << "(";
} else if (Pointee->kind() == NodeKind::FunctionSignature) {
OS << "(";
OB << "(";
const FunctionSignatureNode *Sig =
static_cast<const FunctionSignatureNode *>(Pointee);
outputCallingConvention(OS, Sig->CallConvention);
OS << " ";
outputCallingConvention(OB, Sig->CallConvention);
OB << " ";
}
if (ClassParent) {
ClassParent->output(OS, Flags);
OS << "::";
ClassParent->output(OB, Flags);
OB << "::";
}
switch (Affinity) {
case PointerAffinity::Pointer:
OS << "*";
OB << "*";
break;
case PointerAffinity::Reference:
OS << "&";
OB << "&";
break;
case PointerAffinity::RValueReference:
OS << "&&";
OB << "&&";
break;
default:
assert(false);
}
outputQualifiers(OS, Quals, false, false);
outputQualifiers(OB, Quals, false, false);
}
void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
if (Pointee->kind() == NodeKind::ArrayType ||
Pointee->kind() == NodeKind::FunctionSignature)
OS << ")";
OB << ")";
Pointee->outputPost(OS, Flags);
Pointee->outputPost(OB, Flags);
}
void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
if (!(Flags & OF_NoTagSpecifier)) {
switch (Tag) {
OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
@ -531,59 +538,59 @@ void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
}
OS << " ";
OB << " ";
}
QualifiedName->output(OS, Flags);
outputQualifiers(OS, Quals, true, false);
QualifiedName->output(OB, Flags);
outputQualifiers(OB, Quals, true, false);
}
void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
ElementType->outputPre(OS, Flags);
outputQualifiers(OS, Quals, true, false);
void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
ElementType->outputPre(OB, Flags);
outputQualifiers(OB, Quals, true, false);
}
void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags,
Node *N) const {
assert(N->kind() == NodeKind::IntegerLiteral);
IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
if (ILN->Value != 0)
ILN->output(OS, Flags);
ILN->output(OB, Flags);
}
void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB,
OutputFlags Flags) const {
if (Dimensions->Count == 0)
return;
outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
for (size_t I = 1; I < Dimensions->Count; ++I) {
OS << "][";
outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
OB << "][";
outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
}
}
void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
OS << "[";
outputDimensionsImpl(OS, Flags);
OS << "]";
void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
OB << "[";
outputDimensionsImpl(OB, Flags);
OB << "]";
ElementType->outputPost(OS, Flags);
ElementType->outputPost(OB, Flags);
}
void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Name->output(OS, Flags);
void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
Name->output(OB, Flags);
}
void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
Signature->outputPre(OS, Flags);
outputSpaceIfNecessary(OS);
Name->output(OS, Flags);
Signature->outputPost(OS, Flags);
void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
Signature->outputPre(OB, Flags);
outputSpaceIfNecessary(OB);
Name->output(OB, Flags);
Signature->outputPost(OB, Flags);
}
void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
const char *AccessSpec = nullptr;
bool IsStatic = true;
switch (SC) {
@ -601,53 +608,52 @@ void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
break;
}
if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
OS << AccessSpec << ": ";
OB << AccessSpec << ": ";
if (!(Flags & OF_NoMemberType) && IsStatic)
OS << "static ";
OB << "static ";
if (Type) {
Type->outputPre(OS, Flags);
outputSpaceIfNecessary(OS);
if (!(Flags & OF_NoVariableType) && Type) {
Type->outputPre(OB, Flags);
outputSpaceIfNecessary(OB);
}
Name->output(OS, Flags);
if (Type)
Type->outputPost(OS, Flags);
Name->output(OB, Flags);
if (!(Flags & OF_NoVariableType) && Type)
Type->outputPost(OB, Flags);
}
void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
Identifier->output(OS, Flags);
void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
Identifier->output(OB, Flags);
}
void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
Components->output(OS, Flags, "::");
void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const {
Components->output(OB, Flags, "::");
}
void RttiBaseClassDescriptorNode::output(OutputStream &OS,
void RttiBaseClassDescriptorNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
OS << "`RTTI Base Class Descriptor at (";
OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
OB << "`RTTI Base Class Descriptor at (";
OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
<< this->Flags;
OS << ")'";
OB << ")'";
}
void LocalStaticGuardVariableNode::output(OutputStream &OS,
void LocalStaticGuardVariableNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
Name->output(OS, Flags);
Name->output(OB, Flags);
}
void VcallThunkIdentifierNode::output(OutputStream &OS,
void VcallThunkIdentifierNode::output(OutputBuffer &OB,
OutputFlags Flags) const {
OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
}
void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
outputQualifiers(OS, Quals, false, true);
Name->output(OS, Flags);
void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
outputQualifiers(OB, Quals, false, true);
Name->output(OB, Flags);
if (TargetName) {
OS << "{for `";
TargetName->output(OS, Flags);
OS << "'}";
OB << "{for `";
TargetName->output(OB, Flags);
OB << "'}";
}
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(LLVMDemangle)
set(CMAKE_CXX_STANDARD 17)
add_library(LLVMDemangle STATIC
Demangle/Demangle.cpp
Demangle/ItaniumDemangle.cpp
Demangle/MicrosoftDemangle.cpp
Demangle/MicrosoftDemangleNodes.cpp
)
target_include_directories(LLVMDemangle PUBLIC include)

View File

@ -1,36 +0,0 @@
//===-- Demangle.cpp - Common demangling functions ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file This file contains definitions of common demangling functions.
///
//===----------------------------------------------------------------------===//
#include "llvm/Demangle/Demangle.h"
#include <cstdlib>
static bool isItaniumEncoding(const std::string &MangledName) {
size_t Pos = MangledName.find_first_not_of('_');
// A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'.
return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z';
}
std::string llvm::demangle(const std::string &MangledName) {
char *Demangled;
if (isItaniumEncoding(MangledName))
Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
else
Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr,
nullptr, nullptr);
if (!Demangled)
return MangledName;
std::string Ret = Demangled;
free(Demangled);
return Ret;
}

View File

@ -1,191 +0,0 @@
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Provide some utility classes for use in the demangler(s).
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H
#include "StringView.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST
// has been parsed.
class OutputStream {
char *Buffer = nullptr;
size_t CurrentPosition = 0;
size_t BufferCapacity = 0;
// Ensure there is at least n more positions in buffer.
void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) {
BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition)
BufferCapacity = N + CurrentPosition;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr)
std::terminate();
}
}
void writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case...
if (N == 0) {
*this << '0';
return;
}
char Temp[21];
char *TempPtr = std::end(Temp);
while (N) {
*--TempPtr = '0' + char(N % 10);
N /= 10;
}
// Add negative sign...
if (isNeg)
*--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
}
public:
OutputStream(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
OutputStream() = default;
void reset(char *Buffer_, size_t BufferCapacity_) {
CurrentPosition = 0;
Buffer = Buffer_;
BufferCapacity = BufferCapacity_;
}
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
/// into the pack that we're currently printing.
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) {
size_t Size = R.size();
if (Size == 0)
return *this;
grow(Size);
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size;
return *this;
}
OutputStream &operator+=(char C) {
grow(1);
Buffer[CurrentPosition++] = C;
return *this;
}
OutputStream &operator<<(StringView R) { return (*this += R); }
OutputStream &operator<<(char C) { return (*this += C); }
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this;
}
OutputStream &operator<<(unsigned long long N) {
writeUnsigned(N, false);
return *this;
}
OutputStream &operator<<(long N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
OutputStream &operator<<(int N) {
return this->operator<<(static_cast<long long>(N));
}
OutputStream &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N));
}
size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
}
bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() const { return BufferCapacity; }
};
template <class T> class SwapAndRestore {
T &Restore;
T OriginalValue;
bool ShouldRestore = true;
public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
SwapAndRestore(T &Restore_, T NewVal)
: Restore(Restore_), OriginalValue(Restore) {
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
}
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
};
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END
#endif

View File

@ -53,8 +53,8 @@ else()
endif()
if (NOT USE_SYSTEM_LLVM)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL)
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm-demangle ${CMAKE_CURRENT_BINARY_DIR}/external/llvm-demangle EXCLUDE_FROM_ALL)
set_target_properties(llvm-demangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
else()
find_package(LLVM REQUIRED Demangle)
endif()
@ -163,4 +163,4 @@ if (APPLE)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} llvm-demangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)

View File

@ -67,7 +67,7 @@ add_library(${PROJECT_NAME} SHARED
target_include_directories(${PROJECT_NAME} PRIVATE include)
# Add additional libraries here #
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex LLVMDemangle)
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex llvm-demangle)
# ---- No need to change anything from here downwards unless you know what you're doing ---- #

View File

@ -37,15 +37,21 @@ namespace hex::plugin::builtin {
using namespace hex::literals;
void drawDemangler() {
static std::vector<char> mangledBuffer(0xF'FFFF, 0x00);
static std::string demangledName;
static std::string mangledName, demangledName;
if (ImGui::InputText("hex.builtin.tools.demangler.mangled"_lang, mangledBuffer.data(), 0xF'FFFF)) {
demangledName = llvm::demangle(mangledBuffer.data());
if (ImGui::InputTextWithHint("hex.builtin.tools.demangler.mangled"_lang, "Itanium, MSVC, Dlang & Rust", mangledName)) {
demangledName = llvm::demangle(mangledName);
if (demangledName == mangledName) {
demangledName = "???";
}
}
ImGui::InputText("hex.builtin.tools.demangler.demangled"_lang, demangledName.data(), demangledName.size(), ImGuiInputTextFlags_ReadOnly);
ImGui::NewLine();
ImGui::Header("hex.builtin.tools.demangler.demangled"_lang);
if (ImGui::BeginChild("demangled", ImVec2(0, 200_scaled), true)) {
ImGui::TextFormattedWrapped("{}", demangledName);
}
ImGui::EndChild();
}
void drawASCIITable() {

View File

@ -594,7 +594,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byteverteilung" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC demangler" },
{ "hex.builtin.tools.demangler", "LLVM Demangler" },
{ "hex.builtin.tools.demangler.mangled", "Mangled Namen" },
{ "hex.builtin.tools.demangler.demangled", "Demangled Namen" },
{ "hex.builtin.tools.ascii_table", "ASCII Tabelle" },

View File

@ -598,7 +598,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC demangler" },
{ "hex.builtin.tools.demangler", "LLVM Demangler" },
{ "hex.builtin.tools.demangler.mangled", "Mangled name" },
{ "hex.builtin.tools.demangler.demangled", "Demangled name" },
{ "hex.builtin.tools.ascii_table", "ASCII table" },

View File

@ -602,7 +602,7 @@ namespace hex::plugin::builtin {
//{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC demangler" },
{ "hex.builtin.tools.demangler", "LLVM Demangler" },
{ "hex.builtin.tools.demangler.mangled", "Nome Mangled" },
{ "hex.builtin.tools.demangler.demangled", "Nome Demangled" },
{ "hex.builtin.tools.ascii_table", "Tavola ASCII" },

View File

@ -599,7 +599,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "バイト分布" },
{ "hex.builtin.tools.demangler", "Itanium/MSVCデマングラー" },
{ "hex.builtin.tools.demangler", "LLVMデマングラー" },
{ "hex.builtin.tools.demangler.mangled", "マングリング名" },
{ "hex.builtin.tools.demangler.demangled", "デマングリング名" },
{ "hex.builtin.tools.ascii_table", "ASCIIテーブル" },

View File

@ -594,7 +594,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC demangler" },
{ "hex.builtin.tools.demangler", "LLVM Demangler" },
{ "hex.builtin.tools.demangler.mangled", "Mangled name" },
{ "hex.builtin.tools.demangler.demangled", "Demangled name" },
{ "hex.builtin.tools.ascii_table", "ASCII table" },

View File

@ -599,7 +599,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "字节分布" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC 名还原" },
{ "hex.builtin.tools.demangler", "LLVM 名还原" },
{ "hex.builtin.tools.demangler.mangled", "修饰名" },
{ "hex.builtin.tools.demangler.demangled", "还原名" },
{ "hex.builtin.tools.ascii_table", "ASCII 表" },

View File

@ -595,7 +595,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.nodes.visualizer.byte_distribution.header", "Byte Distribution" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC demangler" },
{ "hex.builtin.tools.demangler", "LLVM Demangler" },
{ "hex.builtin.tools.demangler.mangled", "Mangled name" },
{ "hex.builtin.tools.demangler.demangled", "Demangled name" },
{ "hex.builtin.tools.ascii_table", "ASCII 表" },