1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 13:11:39 +01:00

[llvm-pdbdump] Minor prepatory refactor of Class Def Dumper.

In a followup patch I intend to introduce an additional dumping
mode which dumps a graphical representation of a class's layout.
In preparation for this, the text-based layout printer needs to
be split out from the graphical layout printer, and both need
to be able to use the same code for printing the intro and outro
of a class's definition (e.g. base class list, etc).

This patch does so, and in the process introduces a skeleton
definition for the graphical printer, while currently making
the graphical printer just print nothing.

NFC

llvm-svn: 300134
This commit is contained in:
Zachary Turner 2017-04-12 23:18:51 +00:00
parent 8a8f84f312
commit 89377d6ac2
12 changed files with 323 additions and 134 deletions

View File

@ -95,16 +95,18 @@ public:
uint32_t getClassSize() const { return SizeOf; }
const PDBSymbol &getSymbol() const { return Symbol; }
ArrayRef<std::unique_ptr<StorageItemBase>> layout_items() const {
return ChildStorage;
}
ArrayRef<BaseClassLayout *> base_classes() const { return BaseClasses; }
ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const {
return NonStorageItems;
}
const PDBSymbol &getSymbolBase() const { return SymbolBase; }
protected:
void initializeChildren(const PDBSymbol &Sym);
@ -113,7 +115,7 @@ protected:
uint32_t SizeOf = 0;
std::string Name;
const PDBSymbol &Symbol;
const PDBSymbol &SymbolBase;
BitVector UsedBytes;
std::vector<std::unique_ptr<PDBSymbol>> NonStorageItems;
std::vector<std::unique_ptr<StorageItemBase>> ChildStorage;
@ -124,10 +126,14 @@ protected:
class ClassLayout : public UDTLayoutBase {
public:
explicit ClassLayout(const PDBSymbolTypeUDT &UDT);
explicit ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT);
const PDBSymbolTypeUDT &getClass() const { return UDT; }
private:
std::unique_ptr<PDBSymbolTypeUDT> Type;
std::unique_ptr<PDBSymbolTypeUDT> OwnedStorage;
const PDBSymbolTypeUDT &UDT;
};
class BaseClassLayout : public UDTLayoutBase, public StorageItemBase {
@ -135,6 +141,8 @@ public:
BaseClassLayout(const UDTLayoutBase &Parent,
std::unique_ptr<PDBSymbolTypeBaseClass> Base);
const PDBSymbolTypeBaseClass &getBase() const { return *Base; }
private:
std::unique_ptr<PDBSymbolTypeBaseClass> Base;
bool IsVirtualBase;

View File

@ -89,7 +89,8 @@ VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
VTableType->getPointeeType())) {
VTableFuncs.resize(Shape->getCount());
auto ParentFunctions = Parent.getSymbol().findAllChildren<PDBSymbolFunc>();
auto ParentFunctions =
Parent.getSymbolBase().findAllChildren<PDBSymbolFunc>();
while (auto Func = ParentFunctions->getNext()) {
if (Func->isVirtual()) {
uint32_t Index = Func->getVirtualBaseOffset();
@ -109,15 +110,19 @@ VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name,
uint32_t Size)
: Symbol(Symbol), Name(Name), SizeOf(Size) {
: SymbolBase(Symbol), Name(Name), SizeOf(Size) {
UsedBytes.resize(Size);
ChildrenPerByte.resize(Size);
initializeChildren(Symbol);
}
ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)
: UDTLayoutBase(UDT, UDT.getName(), UDT.getLength()), UDT(UDT) {}
ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
: UDTLayoutBase(*UDT, UDT->getName(), UDT->getLength()),
Type(std::move(UDT)) {}
: ClassLayout(*UDT) {
OwnedStorage = std::move(UDT);
}
BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,
std::unique_ptr<PDBSymbolTypeBaseClass> Base)

View File

@ -1,4 +1,4 @@
; RUN: llvm-pdbdump pretty -classes -class-definitions=layout \
; RUN: llvm-pdbdump pretty -classes -class-definitions=layout-members \
; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t
; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING

View File

@ -18,6 +18,8 @@ add_llvm_tool(llvm-pdbdump
PdbYaml.cpp
PrettyBuiltinDumper.cpp
PrettyClassDefinitionDumper.cpp
PrettyClassLayoutTextDumper.cpp
PrettyClassLayoutGraphicalDumper.cpp
PrettyCompilandDumper.cpp
PrettyEnumDumper.cpp
PrettyExternalSymbolDumper.cpp

View File

@ -10,24 +10,14 @@
#include "PrettyClassDefinitionDumper.h"
#include "LinePrinter.h"
#include "PrettyEnumDumper.h"
#include "PrettyFunctionDumper.h"
#include "PrettyTypedefDumper.h"
#include "PrettyVariableDumper.h"
#include "PrettyClassLayoutGraphicalDumper.h"
#include "PrettyClassLayoutTextDumper.h"
#include "llvm-pdbdump.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Format.h"
@ -42,33 +32,57 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
assert(opts::pretty::ClassFormat !=
opts::pretty::ClassDefinitionFormat::None);
uint32_t Size = Class.getLength();
ClassLayout Layout(Class.clone());
ClassLayout Layout(Class);
if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0))
return;
prettyPrintClassIntro(Layout);
switch (opts::pretty::ClassFormat) {
case opts::pretty::ClassDefinitionFormat::Graphical: {
PrettyClassLayoutGraphicalDumper Dumper(Printer);
DumpedAnything = Dumper.start(Layout);
break;
}
case opts::pretty::ClassDefinitionFormat::Standard:
case opts::pretty::ClassDefinitionFormat::Layout: {
PrettyClassLayoutTextDumper Dumper(Printer);
DumpedAnything |= Dumper.start(Layout);
break;
}
default:
llvm_unreachable("Unreachable!");
}
prettyPrintClassOutro(Layout);
}
void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
DumpedAnything = false;
Printer.NewLine();
uint32_t Size = Layout.getClassSize();
const PDBSymbolTypeUDT &Class = Layout.getClass();
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
<< "]";
auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
if (Bases->getChildCount() > 0) {
uint32_t BaseCount = Layout.base_classes().size();
if (BaseCount > 0) {
Printer.Indent();
Printer.NewLine();
Printer << ":";
uint32_t BaseIndex = 0;
while (auto Base = Bases->getNext()) {
for (auto BC : Layout.base_classes()) {
const auto &Base = BC->getBase();
Printer << " ";
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
if (Base->isVirtualBaseClass())
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
if (Base.isVirtualBaseClass())
WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
if (++BaseIndex < Bases->getChildCount()) {
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
if (++BaseIndex < BaseCount) {
Printer.NewLine();
Printer << ",";
}
@ -78,49 +92,17 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
Printer << " {";
Printer.Indent();
}
// Dump non-layout items first, but only if we're not in layout-only mode.
if (opts::pretty::ClassFormat !=
opts::pretty::ClassDefinitionFormat::Layout) {
for (auto &Other : Layout.other_items())
Other->dump(*this);
}
const BitVector &UseMap = Layout.usedBytes();
int NextUnusedByte = Layout.usedBytes().find_first_unset();
// Next dump items which affect class layout.
for (auto &LayoutItem : Layout.layout_items()) {
if (NextUnusedByte >= 0) {
// If there are padding bytes remaining, see if this field is the first to
// cross a padding boundary, and print a padding field indicator if so.
int Off = LayoutItem->getOffsetInParent();
if (Off > NextUnusedByte) {
uint32_t Amount = Off - NextUnusedByte;
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
<< Amount << " bytes)";
assert(UseMap.find_next(NextUnusedByte) == Off);
NextUnusedByte = UseMap.find_next_unset(Off);
}
}
LayoutItem->getSymbol().dump(*this);
}
if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
<< " bytes)";
DumpedAnything = true;
}
void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) {
Printer.Unindent();
if (DumpedAnything)
Printer.NewLine();
Printer << "}";
Printer.NewLine();
if (Layout.deepPaddingSize() > 0) {
APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / (double)Size);
APFloat Pct(100.0 * (double)Layout.deepPaddingSize() /
(double)Layout.getClassSize());
SmallString<8> PctStr;
Pct.toString(PctStr, 4);
WithColor(Printer, PDB_ColorItem::Padding).get()
@ -129,54 +111,3 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
Printer.NewLine();
}
}
void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
VariableDumper Dumper(Printer);
Dumper.start(Symbol);
DumpedAnything = true;
}
void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
if (Printer.IsSymbolExcluded(Symbol.getName()))
return;
if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
return;
if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
!Symbol.isIntroVirtualFunction())
return;
DumpedAnything = true;
Printer.NewLine();
FunctionDumper Dumper(Printer);
Dumper.start(Symbol, FunctionDumper::PointerType::None);
}
void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {
VariableDumper Dumper(Printer);
Dumper.start(Symbol);
DumpedAnything = true;
}
void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
EnumDumper Dumper(Printer);
Dumper.start(Symbol);
}
void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);
Dumper.start(Symbol);
}
void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}

View File

@ -25,6 +25,7 @@ class BitVector;
namespace pdb {
class ClassLayout;
class LinePrinter;
class ClassDefinitionDumper : public PDBSymDumper {
@ -33,18 +34,10 @@ public:
void start(const PDBSymbolTypeUDT &Exe);
void dump(const PDBSymbolTypeBaseClass &Symbol) override;
void dump(const PDBSymbolData &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolFunc &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
void dump(const PDBSymbolTypeVTable &Symbol) override;
private:
bool maybeDumpSymbol(std::unique_ptr<PDBSymbolData> Data,
const BitVector &Padding, int &NextUnusedByte);
bool maybeDumpSymbol(std::unique_ptr<PDBSymbolFunc> Data);
void prettyPrintClassIntro(const ClassLayout &Class);
void prettyPrintClassOutro(const ClassLayout &Class);
bool DumpedAnything = false;
LinePrinter &Printer;
};

View File

@ -0,0 +1,38 @@
//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "PrettyClassLayoutGraphicalDumper.h"
using namespace llvm;
using namespace llvm::pdb;
PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
bool PrettyClassLayoutGraphicalDumper::start(const ClassLayout &Layout) {
return false;
}
void PrettyClassLayoutGraphicalDumper::dump(
const PDBSymbolTypeBaseClass &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(
const PDBSymbolTypeTypedef &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) {
}

View File

@ -0,0 +1,44 @@
//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H
#include "llvm/ADT/BitVector.h"
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
namespace llvm {
namespace pdb {
class ClassLayout;
class LinePrinter;
class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
public:
explicit PrettyClassLayoutGraphicalDumper(LinePrinter &P);
bool start(const ClassLayout &Layout);
void dump(const PDBSymbolTypeBaseClass &Symbol) override;
void dump(const PDBSymbolData &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolFunc &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
void dump(const PDBSymbolTypeVTable &Symbol) override;
private:
bool DumpedAnything = false;
LinePrinter &Printer;
};
}
}
#endif

View File

@ -0,0 +1,123 @@
//===- PrettyClassLayoutTextDumper.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "PrettyClassLayoutTextDumper.h"
#include "LinePrinter.h"
#include "PrettyEnumDumper.h"
#include "PrettyFunctionDumper.h"
#include "PrettyTypedefDumper.h"
#include "PrettyVariableDumper.h"
#include "llvm-pdbdump.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBExtras.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Format.h"
using namespace llvm;
using namespace llvm::pdb;
PrettyClassLayoutTextDumper::PrettyClassLayoutTextDumper(LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
bool PrettyClassLayoutTextDumper::start(const ClassLayout &Layout) {
if (opts::pretty::ClassFormat ==
opts::pretty::ClassDefinitionFormat::Standard) {
for (auto &Other : Layout.other_items())
Other->dump(*this);
}
const BitVector &UseMap = Layout.usedBytes();
int NextUnusedByte = Layout.usedBytes().find_first_unset();
// Next dump items which affect class layout.
for (auto &LayoutItem : Layout.layout_items()) {
if (NextUnusedByte >= 0) {
// If there are padding bytes remaining, see if this field is the first to
// cross a padding boundary, and print a padding field indicator if so.
int Off = LayoutItem->getOffsetInParent();
if (Off > NextUnusedByte) {
uint32_t Amount = Off - NextUnusedByte;
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
<< Amount << " bytes)";
assert(UseMap.find_next(NextUnusedByte) == Off);
NextUnusedByte = UseMap.find_next_unset(Off);
}
}
LayoutItem->getSymbol().dump(*this);
}
if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
<< " bytes)";
DumpedAnything = true;
}
return DumpedAnything;
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolData &Symbol) {
VariableDumper Dumper(Printer);
Dumper.start(Symbol);
DumpedAnything = true;
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolFunc &Symbol) {
if (Printer.IsSymbolExcluded(Symbol.getName()))
return;
if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
return;
if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
!Symbol.isIntroVirtualFunction())
return;
DumpedAnything = true;
Printer.NewLine();
FunctionDumper Dumper(Printer);
Dumper.start(Symbol, FunctionDumper::PointerType::None);
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeVTable &Symbol) {
VariableDumper Dumper(Printer);
Dumper.start(Symbol);
DumpedAnything = true;
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
EnumDumper Dumper(Printer);
Dumper.start(Symbol);
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);
Dumper.start(Symbol);
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeUDT &Symbol) {}

View File

@ -0,0 +1,44 @@
//===- PrettyClassLayoutTextDumper.h ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTTEXTDUMPER_H
#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTTEXTDUMPER_H
#include "llvm/ADT/BitVector.h"
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
namespace llvm {
namespace pdb {
class ClassLayout;
class LinePrinter;
class PrettyClassLayoutTextDumper : public PDBSymDumper {
public:
PrettyClassLayoutTextDumper(LinePrinter &P);
bool start(const ClassLayout &Layout);
void dump(const PDBSymbolTypeBaseClass &Symbol) override;
void dump(const PDBSymbolData &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolFunc &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
void dump(const PDBSymbolTypeVTable &Symbol) override;
private:
bool DumpedAnything = false;
LinePrinter &Printer;
};
}
}
#endif

View File

@ -126,9 +126,10 @@ cl::opt<ClassDefinitionFormat> ClassFormat(
"class-definitions", cl::desc("Class definition format"),
cl::init(ClassDefinitionFormat::Standard),
cl::values(
clEnumValN(ClassDefinitionFormat::Standard, "full",
"Display complete class definition"),
clEnumValN(ClassDefinitionFormat::Layout, "layout",
clEnumValN(ClassDefinitionFormat::Standard, "all-members",
"Display all class members including data, constants, "
"typedefs, etc"),
clEnumValN(ClassDefinitionFormat::Layout, "layout-members",
"Only display members that contribute to class size."),
clEnumValN(ClassDefinitionFormat::None, "none",
"Don't display class definitions")),

View File

@ -18,7 +18,7 @@ namespace opts {
namespace pretty {
enum class ClassDefinitionFormat { None, Layout, Standard };
enum class ClassDefinitionFormat { None, Layout, Graphical, Standard };
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;