Skip to content

Commit

Permalink
Merged master:304b0ed4039 into amd-gfx:d6da82a01ea
Browse files Browse the repository at this point in the history
Local branch amd-gfx d6da82a Merged master:174322c2737 into amd-gfx:1fc9c9226d7
Remote branch master 304b0ed [yaml2obj] - Move "repeated section/fill name" check earlier.
  • Loading branch information
Sw authored and Sw committed May 23, 2020
2 parents d6da82a + 304b0ed commit 5b87fc6
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 37 deletions.
12 changes: 12 additions & 0 deletions clang-tools-extra/clang-query/Query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
"Set whether to bind the root matcher to \"root\".\n"
" set print-matcher (true|false) "
"Set whether to print the current matcher,\n"
" set traversal <kind> "
"Set traversal kind of clang-query session. Available kinds are:\n"
" AsIs "
"Print and match the AST as clang sees it.\n"
" IgnoreImplicitCastsAndParentheses "
"Omit implicit casts and parens in matching and dumping.\n"
" IgnoreUnlessSpelledInSource "
"Omit AST nodes unless spelled in the source. This mode is the "
"default.\n"
" set output <feature> "
"Set whether to output only <feature> content.\n"
" enable output <feature> "
Expand Down Expand Up @@ -98,6 +107,8 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
OS << "Not a valid top-level matcher.\n";
return false;
}

AST->getASTContext().getParentMapContext().setTraversalKind(QS.TK);
Finder.matchAST(AST->getASTContext());

if (QS.PrintMatcher) {
Expand Down Expand Up @@ -148,6 +159,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
const SourceManager &SM = Ctx.getSourceManager();
ASTDumper Dumper(OS, &Ctx.getCommentCommandTraits(), &SM,
SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy());
Dumper.SetTraversalKind(QS.TK);
Dumper.Visit(BI->second);
OS << "\n";
}
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clang-query/Query.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum QueryKind {
QK_Match,
QK_SetBool,
QK_SetOutputKind,
QK_SetTraversalKind,
QK_EnableOutputKind,
QK_DisableOutputKind,
QK_Quit
Expand Down Expand Up @@ -119,6 +120,10 @@ template <> struct SetQueryKind<OutputKind> {
static const QueryKind value = QK_SetOutputKind;
};

template <> struct SetQueryKind<ast_type_traits::TraversalKind> {
static const QueryKind value = QK_SetTraversalKind;
};

/// Query for "set VAR VALUE".
template <typename T> struct SetQuery : Query {
SetQuery(T QuerySession::*Var, T Value)
Expand Down
25 changes: 24 additions & 1 deletion clang-tools-extra/clang-query/QueryParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,24 @@ template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
llvm_unreachable("Invalid output kind");
}

QueryRef QueryParser::parseSetTraversalKind(
ast_type_traits::TraversalKind QuerySession::*Var) {
StringRef ValStr;
unsigned Value =
LexOrCompleteWord<unsigned>(this, ValStr)
.Case("AsIs", ast_type_traits::TK_AsIs)
.Case("IgnoreImplicitCastsAndParentheses",
ast_type_traits::TK_IgnoreImplicitCastsAndParentheses)
.Case("IgnoreUnlessSpelledInSource",
ast_type_traits::TK_IgnoreUnlessSpelledInSource)
.Default(~0u);
if (Value == ~0u) {
return new InvalidQuery("expected traversal kind, got '" + ValStr + "'");
}
return new SetQuery<ast_type_traits::TraversalKind>(
Var, static_cast<ast_type_traits::TraversalKind>(Value));
}

QueryRef QueryParser::endQuery(QueryRef Q) {
StringRef Extra = Line;
StringRef ExtraTrimmed = Extra.drop_while(
Expand Down Expand Up @@ -171,7 +189,8 @@ enum ParsedQueryVariable {
PQV_Invalid,
PQV_Output,
PQV_BindRoot,
PQV_PrintMatcher
PQV_PrintMatcher,
PQV_Traversal
};

QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
Expand Down Expand Up @@ -272,6 +291,7 @@ QueryRef QueryParser::doParse() {
.Case("output", PQV_Output)
.Case("bind-root", PQV_BindRoot)
.Case("print-matcher", PQV_PrintMatcher)
.Case("traversal", PQV_Traversal)
.Default(PQV_Invalid);
if (VarStr.empty())
return new InvalidQuery("expected variable name");
Expand All @@ -289,6 +309,9 @@ QueryRef QueryParser::doParse() {
case PQV_PrintMatcher:
Q = parseSetBool(&QuerySession::PrintMatcher);
break;
case PQV_Traversal:
Q = parseSetTraversalKind(&QuerySession::TK);
break;
case PQV_Invalid:
llvm_unreachable("Invalid query kind");
}
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clang-query/QueryParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class QueryParser {
template <typename T> struct LexOrCompleteWord;

QueryRef parseSetBool(bool QuerySession::*Var);
QueryRef
parseSetTraversalKind(ast_type_traits::TraversalKind QuerySession::*Var);
template <typename QueryType> QueryRef parseSetOutputKind();
QueryRef completeMatcherExpression();

Expand Down
5 changes: 4 additions & 1 deletion clang-tools-extra/clang-query/QuerySession.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H

#include "clang/AST/ASTTypeTraits.h"
#include "clang/ASTMatchers/Dynamic/VariantValue.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
Expand All @@ -25,7 +26,7 @@ class QuerySession {
QuerySession(llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs)
: ASTs(ASTs), PrintOutput(false), DiagOutput(true),
DetailedASTOutput(false), BindRoot(true), PrintMatcher(false),
Terminate(false) {}
Terminate(false), TK(ast_type_traits::TK_IgnoreUnlessSpelledInSource) {}

llvm::ArrayRef<std::unique_ptr<ASTUnit>> ASTs;

Expand All @@ -36,6 +37,8 @@ class QuerySession {
bool BindRoot;
bool PrintMatcher;
bool Terminate;

ast_type_traits::TraversalKind TK;
llvm::StringMap<ast_matchers::dynamic::VariantValue> NamedValues;
};

Expand Down
27 changes: 27 additions & 0 deletions clang-tools-extra/unittests/clang-query/QueryParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ TEST_F(QueryParserTest, Set) {
ASSERT_TRUE(isa<SetQuery<bool> >(Q));
EXPECT_EQ(&QuerySession::BindRoot, cast<SetQuery<bool> >(Q)->Var);
EXPECT_EQ(true, cast<SetQuery<bool> >(Q)->Value);

Q = parse("set traversal AsIs");
ASSERT_TRUE(isa<SetQuery<ast_type_traits::TraversalKind>>(Q));
EXPECT_EQ(&QuerySession::TK,
cast<SetQuery<ast_type_traits::TraversalKind>>(Q)->Var);
EXPECT_EQ(ast_type_traits::TK_AsIs,
cast<SetQuery<ast_type_traits::TraversalKind>>(Q)->Value);

Q = parse("set traversal NotATraversal");
ASSERT_TRUE(isa<InvalidQuery>(Q));
EXPECT_EQ("expected traversal kind, got 'NotATraversal'",
cast<InvalidQuery>(Q)->ErrStr);
}

TEST_F(QueryParserTest, Match) {
Expand Down Expand Up @@ -197,6 +209,11 @@ TEST_F(QueryParserTest, Complete) {
EXPECT_EQ("utput ", Comps[0].TypedText);
EXPECT_EQ("output", Comps[0].DisplayText);

Comps = QueryParser::complete("set t", 5, QS);
ASSERT_EQ(1u, Comps.size());
EXPECT_EQ("raversal ", Comps[0].TypedText);
EXPECT_EQ("traversal", Comps[0].DisplayText);

Comps = QueryParser::complete("enable ", 7, QS);
ASSERT_EQ(1u, Comps.size());
EXPECT_EQ("output ", Comps[0].TypedText);
Expand All @@ -214,6 +231,16 @@ TEST_F(QueryParserTest, Complete) {
EXPECT_EQ("dump ", Comps[3].TypedText);
EXPECT_EQ("dump", Comps[3].DisplayText);

Comps = QueryParser::complete("set traversal ", 14, QS);
ASSERT_EQ(3u, Comps.size());

EXPECT_EQ("AsIs ", Comps[0].TypedText);
EXPECT_EQ("AsIs", Comps[0].DisplayText);
EXPECT_EQ("IgnoreImplicitCastsAndParentheses ", Comps[1].TypedText);
EXPECT_EQ("IgnoreImplicitCastsAndParentheses", Comps[1].DisplayText);
EXPECT_EQ("IgnoreUnlessSpelledInSource ", Comps[2].TypedText);
EXPECT_EQ("IgnoreUnlessSpelledInSource", Comps[2].DisplayText);

Comps = QueryParser::complete("match while", 11, QS);
ASSERT_EQ(1u, Comps.size());
EXPECT_EQ("Stmt(", Comps[0].TypedText);
Expand Down
68 changes: 37 additions & 31 deletions llvm/lib/ObjectYAML/ELFEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ template <class ELFT> class ELFState {

void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec);

BumpPtrAllocator StringAlloc;
uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align,
llvm::Optional<llvm::yaml::Hex64> Offset);

Expand All @@ -241,18 +242,31 @@ template <class ELFT>
ELFState<ELFT>::ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH)
: Doc(D), ErrHandler(EH) {
std::vector<ELFYAML::Section *> Sections = Doc.getSections();
StringSet<> DocSections;
for (const ELFYAML::Section *Sec : Sections)
if (!Sec->Name.empty())
DocSections.insert(Sec->Name);

// Insert SHT_NULL section implicitly when it is not defined in YAML.
if (Sections.empty() || Sections.front()->Type != ELF::SHT_NULL)
Doc.Chunks.insert(
Doc.Chunks.begin(),
std::make_unique<ELFYAML::Section>(
ELFYAML::Chunk::ChunkKind::RawContent, /*IsImplicit=*/true));

// We add a technical suffix for each unnamed section/fill. It does not affect
// the output, but allows us to map them by name in the code and report better
// error messages.
StringSet<> DocSections;
for (size_t I = 0; I < Doc.Chunks.size(); ++I) {
const std::unique_ptr<ELFYAML::Chunk> &C = Doc.Chunks[I];
if (C->Name.empty()) {
std::string NewName = ELFYAML::appendUniqueSuffix(
/*Name=*/"", "index " + Twine(I));
C->Name = StringRef(NewName).copy(StringAlloc);
assert(ELFYAML::dropUniqueSuffix(C->Name).empty());
}

if (!DocSections.insert(C->Name).second)
reportError("repeated section/fill name: '" + C->Name +
"' at YAML section/fill number " + Twine(I));
}

std::vector<StringRef> ImplicitSections;
if (Doc.DynamicSymbols)
ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"});
Expand Down Expand Up @@ -401,22 +415,28 @@ bool ELFState<ELFT>::initImplicitHeader(ContiguousBlobAccumulator &CBA,
return true;
}

constexpr StringRef SuffixStart = " (";
constexpr char SuffixStart = '(';
constexpr char SuffixEnd = ')';

std::string llvm::ELFYAML::appendUniqueSuffix(StringRef Name,
const Twine &Msg) {
return (Name + SuffixStart + Msg + Twine(SuffixEnd)).str();
// Do not add a space when a Name is empty.
std::string Ret = Name.empty() ? "" : Name.str() + ' ';
return Ret + (Twine(SuffixStart) + Msg + Twine(SuffixEnd)).str();
}

StringRef llvm::ELFYAML::dropUniqueSuffix(StringRef S) {
if (S.empty() || S.back() != SuffixEnd)
return S;

// A special case for empty names. See appendUniqueSuffix() above.
size_t SuffixPos = S.rfind(SuffixStart);
if (SuffixPos == StringRef::npos)
if (SuffixPos == 0)
return "";

if (SuffixPos == StringRef::npos || S[SuffixPos - 1] != ' ')
return S;
return S.substr(0, SuffixPos);
return S.substr(0, SuffixPos - 1);
}

template <class ELFT>
Expand All @@ -426,7 +446,6 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
// valid SHN_UNDEF entry since SHT_NULL == 0.
SHeaders.resize(Doc.getSections().size());

size_t SecNdx = -1;
for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) {
if (ELFYAML::Fill *S = dyn_cast<ELFYAML::Fill>(D.get())) {
S->Offset = alignToOffset(CBA, /*Align=*/1, S->Offset);
Expand All @@ -435,16 +454,16 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
continue;
}

++SecNdx;
ELFYAML::Section *Sec = cast<ELFYAML::Section>(D.get());
if (SecNdx == 0 && Sec->IsImplicit)
bool IsFirstUndefSection = D == Doc.Chunks.front();
if (IsFirstUndefSection && Sec->IsImplicit)
continue;

// We have a few sections like string or symbol tables that are usually
// added implicitly to the end. However, if they are explicitly specified
// in the YAML, we need to write them here. This ensures the file offset
// remains correct.
Elf_Shdr &SHeader = SHeaders[SecNdx];
Elf_Shdr &SHeader = SHeaders[SN2I.get(Sec->Name)];
if (initImplicitHeader(CBA, SHeader, Sec->Name,
Sec->IsImplicit ? nullptr : Sec))
continue;
Expand All @@ -461,7 +480,6 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,

// Set the offset for all sections, except the SHN_UNDEF section with index
// 0 when not explicitly requested.
bool IsFirstUndefSection = SecNdx == 0;
if (!IsFirstUndefSection || Sec->Offset)
SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, Sec->Offset);

Expand Down Expand Up @@ -1420,21 +1438,10 @@ void ELFState<ELFT>::writeFill(ELFYAML::Fill &Fill,

template <class ELFT> void ELFState<ELFT>::buildSectionIndex() {
size_t SecNdx = -1;
StringSet<> Seen;
for (size_t I = 0; I < Doc.Chunks.size(); ++I) {
const std::unique_ptr<ELFYAML::Chunk> &C = Doc.Chunks[I];
bool IsSection = isa<ELFYAML::Section>(C.get());
if (IsSection)
++SecNdx;

if (C->Name.empty())
continue;

if (!Seen.insert(C->Name).second)
reportError("repeated section/fill name: '" + C->Name +
"' at YAML section/fill number " + Twine(I));
if (!IsSection || HasError)
for (const std::unique_ptr<ELFYAML::Chunk> &C : Doc.Chunks) {
if (!isa<ELFYAML::Section>(C.get()))
continue;
++SecNdx;

if (!SN2I.addName(C->Name, SecNdx))
llvm_unreachable("buildSectionIndex() failed");
Expand Down Expand Up @@ -1497,16 +1504,15 @@ template <class ELFT>
bool ELFState<ELFT>::writeELF(raw_ostream &OS, ELFYAML::Object &Doc,
yaml::ErrorHandler EH) {
ELFState<ELFT> State(Doc, EH);
if (State.HasError)
return false;

// Finalize .strtab and .dynstr sections. We do that early because want to
// finalize the string table builders before writing the content of the
// sections that might want to use them.
State.finalizeStrings();

State.buildSectionIndex();
if (State.HasError)
return false;

State.buildSymbolIndexes();

std::vector<Elf_Phdr> PHeaders;
Expand Down
5 changes: 4 additions & 1 deletion llvm/test/tools/yaml2obj/ELF/custom-null-section.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ Sections:

# RUN: not yaml2obj --docnum=6 %s -o %t6 2>&1 | FileCheck %s --check-prefix=CASE4

# CASE4: error: unknown section referenced: '.foo' by YAML section ''
# CASE4: error: unknown section referenced: '.foo' by YAML section '(index 0)'
# CASE4-NEXT: error: unknown section referenced: '.bar' by YAML section '(index 1)'

--- !ELF
FileHeader:
Expand All @@ -139,6 +140,8 @@ FileHeader:
Sections:
- Type: SHT_NULL
Link: .foo
- Type: SHT_NULL
Link: .bar

## Check that null section fields are set to zero, if they are unspecified.

Expand Down
12 changes: 9 additions & 3 deletions llvm/test/tools/yaml2obj/ELF/section-link.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ Sections:

# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=ERR

# ERR: error: unknown section referenced: '.unknown1' by YAML section '.foo'
# ERR: error: unknown section referenced: '.unknown2' by YAML section '.bar'
# ERR: error: unknown section referenced: '.unknown1' by YAML section '.foo'
# ERR-NEXT: error: unknown section referenced: '.unknown2' by YAML section '(index 2)'
# ERR-NEXT: error: unknown section referenced: '.unknown3' by YAML section '.bar'
# ERR-NEXT: error: unknown section referenced: '.unknown4' by YAML section '(index 4)'

--- !ELF
FileHeader:
Expand All @@ -41,9 +43,13 @@ Sections:
- Name: .foo
Type: SHT_PROGBITS
Link: .unknown1
- Type: SHT_PROGBITS
Link: .unknown2
- Name: .bar
Type: SHT_PROGBITS
Link: .unknown2
Link: .unknown3
- Type: SHT_PROGBITS
Link: .unknown4

## Check we link SHT_GROUP to a symbol table by default if it exists.
## Also, check we can set an arbitrary value for sh_link.
Expand Down

0 comments on commit 5b87fc6

Please sign in to comment.