Merge llvm-project 12.0.0 release

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-12.0.0-0-gd28af7c654d8, a.k.a. 12.0.0 release.

PR:		255570
MFC after:	6 weeks
This commit is contained in:
Dimitry Andric 2021-04-26 13:23:24 +02:00
commit d409305fa3
269 changed files with 7493 additions and 7942 deletions

View File

@ -538,6 +538,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// need them (like static local vars).
llvm::MapVector<const NamedDecl *, unsigned> MangleNumbers;
llvm::MapVector<const VarDecl *, unsigned> StaticLocalNumbers;
/// Mapping the associated device lambda mangling number if present.
mutable llvm::DenseMap<const CXXRecordDecl *, unsigned>
DeviceLambdaManglingNumbers;
/// Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.

View File

@ -1276,15 +1276,12 @@ class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> {
EvaluatedStmt *getEvaluatedStmt() const;
/// Attempt to evaluate the value of the initializer attached to this
/// declaration, and produce notes explaining why it cannot be evaluated.
/// Returns a pointer to the value if evaluation succeeded, 0 otherwise.
/// declaration, and produce notes explaining why it cannot be evaluated or is
/// not a constant expression. Returns a pointer to the value if evaluation
/// succeeded, 0 otherwise.
APValue *evaluateValue() const;
APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
private:
APValue *evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
bool IsConstantInitialization) const;
public:
/// Return the already-evaluated value of this variable's
/// initializer, or NULL if the value is not yet known. Returns pointer
/// to untyped APValue if the value could not be evaluated.

View File

@ -1735,6 +1735,12 @@ class CXXRecordDecl : public RecordDecl {
getLambdaData().HasKnownInternalLinkage = HasKnownInternalLinkage;
}
/// Set the device side mangling number.
void setDeviceLambdaManglingNumber(unsigned Num) const;
/// Retrieve the device side mangling number.
unsigned getDeviceLambdaManglingNumber() const;
/// Returns the inheritance model used for this record.
MSInheritanceModel getMSInheritanceModel() const;

View File

@ -699,8 +699,7 @@ class Expr : public ValueStmt {
/// notes will be produced if the expression is not a constant expression.
bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
bool IsConstantInitializer) const;
SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
/// EvaluateWithSubstitution - Evaluate an expression as if from the context
/// of a call to the given function with the given arguments, inside an

View File

@ -96,6 +96,9 @@ class MangleContext {
virtual bool shouldMangleCXXName(const NamedDecl *D) = 0;
virtual bool shouldMangleStringLiteral(const StringLiteral *SL) = 0;
virtual bool isDeviceMangleContext() const { return false; }
virtual void setDeviceMangleContext(bool) {}
// FIXME: consider replacing raw_ostream & with something like SmallString &.
void mangleName(GlobalDecl GD, raw_ostream &);
virtual void mangleCXXName(GlobalDecl GD, raw_ostream &) = 0;

View File

@ -52,6 +52,11 @@ class MangleNumberingContext {
/// this context.
virtual unsigned getManglingNumber(const TagDecl *TD,
unsigned MSLocalManglingNumber) = 0;
/// Retrieve the mangling number of a new lambda expression with the
/// given call operator within the device context. No device number is
/// assigned if there's no device numbering context is associated.
virtual unsigned getDeviceManglingNumber(const CXXMethodDecl *) { return 0; }
};
} // end namespace clang

View File

@ -186,6 +186,9 @@ template <typename Derived> class RecursiveASTVisitor {
/// code, e.g., implicit constructors and destructors.
bool shouldVisitImplicitCode() const { return false; }
/// Return whether this visitor should recurse into lambda body
bool shouldVisitLambdaBody() const { return true; }
/// Return whether this visitor should traverse post-order.
bool shouldTraversePostOrder() const { return false; }
@ -2057,6 +2060,15 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// by clang.
(!D->isDefaulted() || getDerived().shouldVisitImplicitCode());
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
if (const CXXRecordDecl *RD = MD->getParent()) {
if (RD->isLambda() &&
declaresSameEntity(RD->getLambdaCallOperator(), MD)) {
VisitBody = VisitBody && getDerived().shouldVisitLambdaBody();
}
}
}
if (VisitBody) {
TRY_TO(TraverseStmt(D->getBody())); // Function body.
}

View File

@ -344,7 +344,7 @@ extern const internal::VariadicAllOfMatcher<Decl> decl;
/// int number = 42;
/// auto [foo, bar] = std::make_pair{42, 42};
/// \endcode
extern const internal::VariadicAllOfMatcher<DecompositionDecl>
extern const internal::VariadicDynCastAllOfMatcher<Decl, DecompositionDecl>
decompositionDecl;
/// Matches a declaration of a linkage specification.

View File

@ -266,6 +266,9 @@ CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer.
CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer.
CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
/// Treat loops as finite: language, always, never.
ENUM_CODEGENOPT(FiniteLoops, FiniteLoopsKind, 2, FiniteLoopsKind::Language)
/// Attempt to use register sized accesses to bit-fields in structures, when
/// possible.
CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0)

View File

@ -140,6 +140,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
All, // Keep all frame pointers.
};
enum FiniteLoopsKind {
Language, // Not specified, use language standard.
Always, // All loops are assumed to be finite.
Never, // No loop is assumed to be finite.
};
/// The code model to use (-mcmodel).
std::string CodeModel;

View File

@ -1147,7 +1147,7 @@ def fprofile_update_EQ : Joined<["-"], "fprofile-update=">,
defm pseudo_probe_for_profiling : BoolFOption<"pseudo-probe-for-profiling",
CodeGenOpts<"PseudoProbeForProfiling">, DefaultFalse,
PosFlag<SetTrue, [], "Emit">, NegFlag<SetFalse, [], "Do not emit">,
BothFlags<[NoXarchOption, CC1Option], " pseudo probes for sample profiler">>;
BothFlags<[NoXarchOption, CC1Option], " pseudo probes for sample profiling">>;
def forder_file_instrumentation : Flag<["-"], "forder-file-instrumentation">,
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
HelpText<"Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
@ -2410,6 +2410,11 @@ def fno_unroll_loops : Flag<["-"], "fno-unroll-loops">, Group<f_Group>,
defm reroll_loops : BoolFOption<"reroll-loops",
CodeGenOpts<"RerollLoops">, DefaultFalse,
PosFlag<SetTrue, [CC1Option], "Turn on loop reroller">, NegFlag<SetFalse>>;
def ffinite_loops: Flag<["-"], "ffinite-loops">, Group<f_Group>,
HelpText<"Assume all loops are finite.">, Flags<[CC1Option]>;
def fno_finite_loops: Flag<["-"], "fno-finite-loops">, Group<f_Group>,
HelpText<"Do not assume that any loop is finite.">, Flags<[CC1Option]>;
def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,

View File

@ -39,17 +39,14 @@ namespace clang {
assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
"outside an ISO C/C++ variadic "
"macro definition!");
assert(
!Ident__VA_OPT__ ||
(Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"));
assert(Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!");
}
/// Client code should call this function just before the Preprocessor is
/// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
void enterScope() {
Ident__VA_ARGS__->setIsPoisoned(false);
if (Ident__VA_OPT__)
Ident__VA_OPT__->setIsPoisoned(false);
Ident__VA_OPT__->setIsPoisoned(false);
}
/// Client code should call this function as soon as the Preprocessor has
@ -58,8 +55,7 @@ namespace clang {
/// (might be explicitly called, and then reinvoked via the destructor).
void exitScope() {
Ident__VA_ARGS__->setIsPoisoned(true);
if (Ident__VA_OPT__)
Ident__VA_OPT__->setIsPoisoned(true);
Ident__VA_OPT__->setIsPoisoned(true);
}
~VariadicMacroScopeGuard() { exitScope(); }

View File

@ -6558,7 +6558,7 @@ class Sema final {
/// Number lambda for linkage purposes if necessary.
void handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
Optional<std::tuple<unsigned, bool, Decl *>> Mangling = None);
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling = None);
/// Endow the lambda scope info with the relevant properties.
void buildLambdaScope(sema::LambdaScopeInfo *LSI,
@ -11948,8 +11948,8 @@ class Sema final {
/// if (diagIfOpenMPDeviceCode(Loc, diag::err_vla_unsupported))
/// return ExprError();
/// // Otherwise, continue parsing as normal.
SemaDiagnosticBuilder diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID);
SemaDiagnosticBuilder
diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID, FunctionDecl *FD);
/// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
/// context is "used as host code".
@ -11965,17 +11965,19 @@ class Sema final {
/// return ExprError();
/// // Otherwise, continue parsing as normal.
SemaDiagnosticBuilder diagIfOpenMPHostCode(SourceLocation Loc,
unsigned DiagID);
unsigned DiagID, FunctionDecl *FD);
SemaDiagnosticBuilder targetDiag(SourceLocation Loc, unsigned DiagID);
SemaDiagnosticBuilder targetDiag(SourceLocation Loc, unsigned DiagID,
FunctionDecl *FD = nullptr);
SemaDiagnosticBuilder targetDiag(SourceLocation Loc,
const PartialDiagnostic &PD) {
return targetDiag(Loc, PD.getDiagID()) << PD;
const PartialDiagnostic &PD,
FunctionDecl *FD = nullptr) {
return targetDiag(Loc, PD.getDiagID(), FD) << PD;
}
/// Check if the expression is allowed to be used in expressions for the
/// offloading devices.
void checkDeviceDecl(const ValueDecl *D, SourceLocation Loc);
void checkDeviceDecl(ValueDecl *D, SourceLocation Loc);
enum CUDAFunctionTarget {
CFT_Device,

View File

@ -2848,6 +2848,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
return CDeclOrErr.takeError();
D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr,
DCXX->hasKnownLambdaInternalLinkage());
D2CXX->setDeviceLambdaManglingNumber(
DCXX->getDeviceLambdaManglingNumber());
} else if (DCXX->isInjectedClassName()) {
// We have to be careful to do a similar dance to the one in
// Sema::ActOnStartCXXMemberDeclarations

View File

@ -22,8 +22,9 @@ class ASTContext;
class CXXConstructorDecl;
class DeclaratorDecl;
class Expr;
class MemberPointerType;
class MangleContext;
class MangleNumberingContext;
class MemberPointerType;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
@ -75,6 +76,8 @@ class CXXABI {
/// Creates an instance of a C++ ABI class.
CXXABI *CreateItaniumCXXABI(ASTContext &Ctx);
CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx);
std::unique_ptr<MangleNumberingContext>
createItaniumNumberingContext(MangleContext *);
}
#endif

View File

@ -2384,11 +2384,11 @@ EvaluatedStmt *VarDecl::getEvaluatedStmt() const {
APValue *VarDecl::evaluateValue() const {
SmallVector<PartialDiagnosticAt, 8> Notes;
return evaluateValueImpl(Notes, hasConstantInitialization());
return evaluateValue(Notes);
}
APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
bool IsConstantInitialization) const {
APValue *VarDecl::evaluateValue(
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
const auto *Init = cast<Expr>(Eval->Value);
@ -2407,16 +2407,8 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
Eval->IsEvaluating = true;
ASTContext &Ctx = getASTContext();
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, Ctx, this, Notes,
IsConstantInitialization);
// In C++11, this isn't a constant initializer if we produced notes. In that
// case, we can't keep the result, because it may only be correct under the
// assumption that the initializer is a constant context.
if (IsConstantInitialization && Ctx.getLangOpts().CPlusPlus11 &&
!Notes.empty())
Result = false;
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
this, Notes);
// Ensure the computed APValue is cleaned up later if evaluation succeeded,
// or that it's empty (so that there's nothing to clean up) if evaluation
@ -2424,7 +2416,7 @@ APValue *VarDecl::evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
if (!Result)
Eval->Evaluated = APValue();
else if (Eval->Evaluated.needsCleanup())
Ctx.addDestruction(&Eval->Evaluated);
getASTContext().addDestruction(&Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
@ -2478,14 +2470,7 @@ bool VarDecl::checkForConstantInitialization(
assert(!cast<Expr>(Eval->Value)->isValueDependent());
// Evaluate the initializer to check whether it's a constant expression.
Eval->HasConstantInitialization =
evaluateValueImpl(Notes, true) && Notes.empty();
// If evaluation as a constant initializer failed, allow re-evaluation as a
// non-constant initializer if we later find we want the value.
if (!Eval->HasConstantInitialization)
Eval->WasEvaluated = false;
Eval->HasConstantInitialization = evaluateValue(Notes) && Notes.empty();
return Eval->HasConstantInitialization;
}

View File

@ -1593,6 +1593,20 @@ Decl *CXXRecordDecl::getLambdaContextDecl() const {
return getLambdaData().ContextDecl.get(Source);
}
void CXXRecordDecl::setDeviceLambdaManglingNumber(unsigned Num) const {
assert(isLambda() && "Not a lambda closure type!");
if (Num)
getASTContext().DeviceLambdaManglingNumbers[this] = Num;
}
unsigned CXXRecordDecl::getDeviceLambdaManglingNumber() const {
assert(isLambda() && "Not a lambda closure type!");
auto I = getASTContext().DeviceLambdaManglingNumbers.find(this);
if (I != getASTContext().DeviceLambdaManglingNumbers.end())
return I->second;
return 0;
}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T =
cast<CXXConversionDecl>(Conv->getUnderlyingDecl()->getAsFunction())

View File

@ -3302,9 +3302,12 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Check that we can fold the initializer. In C++, we will have already done
// this in the cases where it matters for conformance.
if (!VD->evaluateValue()) {
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD;
SmallVector<PartialDiagnosticAt, 8> Notes;
if (!VD->evaluateValue(Notes)) {
Info.FFDiag(E, diag::note_constexpr_var_init_non_constant,
Notes.size() + 1) << VD;
NoteLValueLocation(Info, Base);
Info.addNotes(Notes);
return false;
}
@ -3497,8 +3500,8 @@ static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E, AccessKinds AK,
static bool lifetimeStartedInEvaluation(EvalInfo &Info,
APValue::LValueBase Base,
bool MutableSubobject = false) {
// A temporary we created.
if (Base.getCallIndex())
// A temporary or transient heap allocation we created.
if (Base.getCallIndex() || Base.is<DynamicAllocLValue>())
return true;
switch (Info.IsEvaluatingDecl) {
@ -10009,6 +10012,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
auto *CaptureInitIt = E->capture_init_begin();
const LambdaCapture *CaptureIt = ClosureClass->captures_begin();
bool Success = true;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(ClosureClass);
for (const auto *Field : ClosureClass->fields()) {
assert(CaptureInitIt != E->capture_init_end());
// Get the initializer for this field
@ -10019,8 +10023,13 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
if (!CurFieldInit)
return Error(E);
LValue Subobject = This;
if (!HandleLValueMember(Info, E, Subobject, Field, &Layout))
return false;
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
if (!EvaluateInPlace(FieldVal, Info, This, CurFieldInit)) {
if (!EvaluateInPlace(FieldVal, Info, Subobject, CurFieldInit)) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@ -14786,11 +14795,14 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
static bool EvaluateDestruction(const ASTContext &Ctx, APValue::LValueBase Base,
APValue DestroyedValue, QualType Type,
SourceLocation Loc, Expr::EvalStatus &EStatus) {
EvalInfo Info(Ctx, EStatus, EvalInfo::EM_ConstantExpression);
SourceLocation Loc, Expr::EvalStatus &EStatus,
bool IsConstantDestruction) {
EvalInfo Info(Ctx, EStatus,
IsConstantDestruction ? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
Info.setEvaluatingDecl(Base, DestroyedValue,
EvalInfo::EvaluatingDeclKind::Dtor);
Info.InConstantContext = true;
Info.InConstantContext = IsConstantDestruction;
LValue LVal;
LVal.set(Base);
@ -14844,7 +14856,8 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
// If this is a class template argument, it's required to have constant
// destruction too.
if (Kind == ConstantExprKind::ClassTemplateArgument &&
(!EvaluateDestruction(Ctx, Base, Result.Val, T, getBeginLoc(), Result) ||
(!EvaluateDestruction(Ctx, Base, Result.Val, T, getBeginLoc(), Result,
true) ||
Result.HasSideEffects)) {
// FIXME: Prefix a note to indicate that the problem is lack of constant
// destruction.
@ -14856,8 +14869,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
SmallVectorImpl<PartialDiagnosticAt> &Notes,
bool IsConstantInitialization) const {
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@ -14870,12 +14882,11 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
EvalInfo Info(Ctx, EStatus,
(IsConstantInitialization && Ctx.getLangOpts().CPlusPlus11)
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
EvalInfo Info(Ctx, EStatus, VD->isConstexpr()
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
Info.setEvaluatingDecl(VD, Value);
Info.InConstantContext = IsConstantInitialization;
Info.InConstantContext = true;
SourceLocation DeclLoc = VD->getLocation();
QualType DeclTy = VD->getType();
@ -14910,6 +14921,10 @@ bool VarDecl::evaluateDestruction(
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
// Only treat the destruction as constant destruction if we formally have
// constant initialization (or are usable in a constant expression).
bool IsConstantDestruction = hasConstantInitialization();
// Make a copy of the value for the destructor to mutate, if we know it.
// Otherwise, treat the value as default-initialized; if the destructor works
// anyway, then the destruction is constant (and must be essentially empty).
@ -14920,7 +14935,8 @@ bool VarDecl::evaluateDestruction(
return false;
if (!EvaluateDestruction(getASTContext(), this, std::move(DestroyedValue),
getType(), getLocation(), EStatus) ||
getType(), getLocation(), EStatus,
IsConstantDestruction) ||
EStatus.HasSideEffects)
return false;

View File

@ -258,3 +258,9 @@ class ItaniumCXXABI : public CXXABI {
CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) {
return new ItaniumCXXABI(Ctx);
}
std::unique_ptr<MangleNumberingContext>
clang::createItaniumNumberingContext(MangleContext *Mangler) {
return std::make_unique<ItaniumNumberingContext>(
cast<ItaniumMangleContext>(Mangler));
}

View File

@ -125,6 +125,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
bool IsDevCtx = false;
public:
explicit ItaniumMangleContextImpl(ASTContext &Context,
DiagnosticsEngine &Diags)
@ -137,6 +139,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
bool shouldMangleStringLiteral(const StringLiteral *) override {
return false;
}
bool isDeviceMangleContext() const override { return IsDevCtx; }
void setDeviceMangleContext(bool IsDev) override { IsDevCtx = IsDev; }
void mangleCXXName(GlobalDecl GD, raw_ostream &) override;
void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
raw_ostream &) override;
@ -546,8 +552,8 @@ class CXXNameMangler {
unsigned knownArity);
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
void mangleDeclRefExpr(const NamedDecl *D);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
void mangleExpression(const Expr *E, unsigned Arity = UnknownArity,
bool AsTemplateArg = false);
void mangleCXXCtorType(CXXCtorType T, const CXXRecordDecl *InheritedFrom);
void mangleCXXDtorType(CXXDtorType T);
@ -558,6 +564,7 @@ class CXXNameMangler {
unsigned NumTemplateArgs);
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
void mangleTemplateArgExpr(const Expr *E);
void mangleValueInTemplateArg(QualType T, const APValue &V, bool TopLevel,
bool NeedExactType = false);
@ -726,9 +733,17 @@ void CXXNameMangler::mangleFunctionEncodingBareType(const FunctionDecl *FD) {
EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I);
if (!EIA)
continue;
Out << 'X';
mangleExpression(EIA->getCond());
Out << 'E';
if (Context.getASTContext().getLangOpts().getClangABICompat() >
LangOptions::ClangABI::Ver11) {
mangleTemplateArgExpr(EIA->getCond());
} else {
// Prior to Clang 12, we hardcoded the X/E around enable-if's argument,
// even though <template-arg> should not include an X/E around
// <expr-primary>.
Out << 'X';
mangleExpression(EIA->getCond());
Out << 'E';
}
}
Out << 'E';
FunctionTypeDepth.pop(Saved);
@ -1837,7 +1852,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// (in lexical order) with that same <lambda-sig> and context.
//
// The AST keeps track of the number for us.
unsigned Number = Lambda->getLambdaManglingNumber();
//
// In CUDA/HIP, to ensure the consistent lamba numbering between the device-
// and host-side compilations, an extra device mangle context may be created
// if the host-side CXX ABI has different numbering for lambda. In such case,
// if the mangle context is that device-side one, use the device-side lambda
// mangling number for this lambda.
unsigned Number = Context.isDeviceMangleContext()
? Lambda->getDeviceLambdaManglingNumber()
: Lambda->getLambdaManglingNumber();
assert(Number > 0 && "Lambda should be mangled as an unnamed class");
if (Number > 1)
mangleNumber(Number - 2);
@ -3528,8 +3551,8 @@ void CXXNameMangler::mangleType(const DependentSizedMatrixType *T) {
Out << "u" << VendorQualifier.size() << VendorQualifier;
Out << "I";
mangleTemplateArg(T->getRowExpr(), false);
mangleTemplateArg(T->getColumnExpr(), false);
mangleTemplateArgExpr(T->getRowExpr());
mangleTemplateArgExpr(T->getColumnExpr());
mangleType(T->getElementType());
Out << "E";
}
@ -3871,33 +3894,8 @@ void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) {
mangleExpression(InitList->getInit(i));
}
void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {
switch (D->getKind()) {
default:
// <expr-primary> ::= L <mangled-name> E # external name
Out << 'L';
mangle(D);
Out << 'E';
break;
case Decl::ParmVar:
mangleFunctionParam(cast<ParmVarDecl>(D));
break;
case Decl::EnumConstant: {
const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
mangleIntegerLiteral(ED->getType(), ED->getInitVal());
break;
}
case Decl::NonTypeTemplateParm:
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
mangleTemplateParameter(PD->getDepth(), PD->getIndex());
break;
}
}
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
bool AsTemplateArg) {
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <trinary operator-name> <expression> <expression> <expression>
@ -3911,18 +3909,64 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// ::= at <type> # alignof (a type)
// ::= <template-param>
// ::= <function-param>
// ::= fpT # 'this' expression (part of <function-param>)
// ::= sr <type> <unqualified-name> # dependent name
// ::= sr <type> <unqualified-name> <template-args> # dependent template-id
// ::= ds <expression> <expression> # expr.*expr
// ::= sZ <template-param> # size of a parameter pack
// ::= sZ <function-param> # size of a function parameter pack
// ::= u <source-name> <template-arg>* E # vendor extended expression
// ::= <expr-primary>
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type <value float> E # floating literal
// ::= L <type> <value float> E # floating literal
// ::= L <type> <string type> E # string literal
// ::= L <nullptr type> E # nullptr literal "LDnE"
// ::= L <pointer type> 0 E # null pointer template argument
// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C99); not used by clang
// ::= L <mangled-name> E # external name
// ::= fpT # 'this' expression
QualType ImplicitlyConvertedToType;
// A top-level expression that's not <expr-primary> needs to be wrapped in
// X...E in a template arg.
bool IsPrimaryExpr = true;
auto NotPrimaryExpr = [&] {
if (AsTemplateArg && IsPrimaryExpr)
Out << 'X';
IsPrimaryExpr = false;
};
auto MangleDeclRefExpr = [&](const NamedDecl *D) {
switch (D->getKind()) {
default:
// <expr-primary> ::= L <mangled-name> E # external name
Out << 'L';
mangle(D);
Out << 'E';
break;
case Decl::ParmVar:
NotPrimaryExpr();
mangleFunctionParam(cast<ParmVarDecl>(D));
break;
case Decl::EnumConstant: {
// <expr-primary>
const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
mangleIntegerLiteral(ED->getType(), ED->getInitVal());
break;
}
case Decl::NonTypeTemplateParm:
NotPrimaryExpr();
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
mangleTemplateParameter(PD->getDepth(), PD->getIndex());
break;
}
};
// 'goto recurse' is used when handling a simple "unwrapping" node which
// produces no output, where ImplicitlyConvertedToType and AsTemplateArg need
// to be preserved.
recurse:
switch (E->getStmtClass()) {
case Expr::NoStmtClass:
@ -3994,6 +4038,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::SourceLocExprClass:
case Expr::BuiltinBitCastExprClass:
{
NotPrimaryExpr();
if (!NullOut) {
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
@ -4001,33 +4046,48 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
"cannot yet mangle expression type %0");
Diags.Report(E->getExprLoc(), DiagID)
<< E->getStmtClassName() << E->getSourceRange();
return;
}
break;
}
case Expr::CXXUuidofExprClass: {
NotPrimaryExpr();
const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E);
if (UE->isTypeOperand()) {
QualType UuidT = UE->getTypeOperand(Context.getASTContext());
Out << "u8__uuidoft";
mangleType(UuidT);
// As of clang 12, uuidof uses the vendor extended expression
// mangling. Previously, it used a special-cased nonstandard extension.
if (Context.getASTContext().getLangOpts().getClangABICompat() >
LangOptions::ClangABI::Ver11) {
Out << "u8__uuidof";
if (UE->isTypeOperand())
mangleType(UE->getTypeOperand(Context.getASTContext()));
else
mangleTemplateArgExpr(UE->getExprOperand());
Out << 'E';
} else {
Expr *UuidExp = UE->getExprOperand();
Out << "u8__uuidofz";
mangleExpression(UuidExp, Arity);
if (UE->isTypeOperand()) {
QualType UuidT = UE->getTypeOperand(Context.getASTContext());
Out << "u8__uuidoft";
mangleType(UuidT);
} else {
Expr *UuidExp = UE->getExprOperand();
Out << "u8__uuidofz";
mangleExpression(UuidExp);
}
}
break;
}
// Even gcc-4.5 doesn't mangle this.
case Expr::BinaryConditionalOperatorClass: {
NotPrimaryExpr();
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID =
Diags.getCustomDiagID(DiagnosticsEngine::Error,
"?: operator with omitted middle operand cannot be mangled");
Diags.Report(E->getExprLoc(), DiagID)
<< E->getStmtClassName() << E->getSourceRange();
break;
return;
}
// These are used for internal purposes and cannot be meaningfully mangled.
@ -4035,6 +4095,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
case Expr::InitListExprClass: {
NotPrimaryExpr();
Out << "il";
mangleInitListElements(cast<InitListExpr>(E));
Out << "E";
@ -4042,6 +4103,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::DesignatedInitExprClass: {
NotPrimaryExpr();
auto *DIE = cast<DesignatedInitExpr>(E);
for (const auto &Designator : DIE->designators()) {
if (Designator.isFieldDesignator()) {
@ -4063,27 +4125,27 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXDefaultArgExprClass:
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
break;
E = cast<CXXDefaultArgExpr>(E)->getExpr();
goto recurse;
case Expr::CXXDefaultInitExprClass:
mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity);
break;
E = cast<CXXDefaultInitExpr>(E)->getExpr();
goto recurse;
case Expr::CXXStdInitializerListExprClass:
mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
break;
E = cast<CXXStdInitializerListExpr>(E)->getSubExpr();
goto recurse;
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
break;
E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
goto recurse;
case Expr::UserDefinedLiteralClass:
// We follow g++'s approach of mangling a UDL as a call to the literal
// operator.
case Expr::CXXMemberCallExprClass: // fallthrough
case Expr::CallExprClass: {
NotPrimaryExpr();
const CallExpr *CE = cast<CallExpr>(E);
// <expression> ::= cp <simple-id> <expression>* E
@ -4114,6 +4176,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXNewExprClass: {
NotPrimaryExpr();
const CXXNewExpr *New = cast<CXXNewExpr>(E);
if (New->isGlobalNew()) Out << "gs";
Out << (New->isArray() ? "na" : "nw");
@ -4149,6 +4212,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXPseudoDestructorExprClass: {
NotPrimaryExpr();
const auto *PDE = cast<CXXPseudoDestructorExpr>(E);
if (const Expr *Base = PDE->getBase())
mangleMemberExprBase(Base, PDE->isArrow());
@ -4175,6 +4239,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::MemberExprClass: {
NotPrimaryExpr();
const MemberExpr *ME = cast<MemberExpr>(E);
mangleMemberExpr(ME->getBase(), ME->isArrow(),
ME->getQualifier(), nullptr,
@ -4185,6 +4250,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::UnresolvedMemberExprClass: {
NotPrimaryExpr();
const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
ME->isArrow(), ME->getQualifier(), nullptr,
@ -4195,6 +4261,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXDependentScopeMemberExprClass: {
NotPrimaryExpr();
const CXXDependentScopeMemberExpr *ME
= cast<CXXDependentScopeMemberExpr>(E);
mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(),
@ -4207,6 +4274,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::UnresolvedLookupExprClass: {
NotPrimaryExpr();
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
mangleUnresolvedName(ULE->getQualifier(), ULE->getName(),
ULE->getTemplateArgs(), ULE->getNumTemplateArgs(),
@ -4215,6 +4283,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXUnresolvedConstructExprClass: {
NotPrimaryExpr();
const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
unsigned N = CE->getNumArgs();
@ -4225,7 +4294,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleType(CE->getType());
mangleInitListElements(IL);
Out << "E";
return;
break;
}
Out << "cv";
@ -4237,14 +4306,17 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXConstructExprClass: {
// An implicit cast is silent, thus may contain <expr-primary>.
const auto *CE = cast<CXXConstructExpr>(E);
if (!CE->isListInitialization() || CE->isStdInitListInitialization()) {
assert(
CE->getNumArgs() >= 1 &&
(CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) &&
"implicit CXXConstructExpr must have one argument");
return mangleExpression(cast<CXXConstructExpr>(E)->getArg(0));
E = cast<CXXConstructExpr>(E)->getArg(0);
goto recurse;
}
NotPrimaryExpr();
Out << "il";
for (auto *E : CE->arguments())
mangleExpression(E);
@ -4253,6 +4325,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXTemporaryObjectExprClass: {
NotPrimaryExpr();
const auto *CE = cast<CXXTemporaryObjectExpr>(E);
unsigned N = CE->getNumArgs();
bool List = CE->isListInitialization();
@ -4282,17 +4355,20 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXScalarValueInitExprClass:
NotPrimaryExpr();
Out << "cv";
mangleType(E->getType());
Out << "_E";
break;
case Expr::CXXNoexceptExprClass:
NotPrimaryExpr();
Out << "nx";
mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand());
break;
case Expr::UnaryExprOrTypeTraitExprClass: {
// Non-instantiation-dependent traits are an <expr-primary> integer literal.
const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E);
if (!SAE->isInstantiationDependent()) {
@ -4312,13 +4388,41 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
break;
}
NotPrimaryExpr(); // But otherwise, they are not.
auto MangleAlignofSizeofArg = [&] {
if (SAE->isArgumentType()) {
Out << 't';
mangleType(SAE->getArgumentType());
} else {
Out << 'z';
mangleExpression(SAE->getArgumentExpr());
}
};
switch(SAE->getKind()) {
case UETT_SizeOf:
Out << 's';
MangleAlignofSizeofArg();
break;
case UETT_PreferredAlignOf:
// As of clang 12, we mangle __alignof__ differently than alignof. (They
// have acted differently since Clang 8, but were previously mangled the
// same.)
if (Context.getASTContext().getLangOpts().getClangABICompat() >
LangOptions::ClangABI::Ver11) {
Out << "u11__alignof__";
if (SAE->isArgumentType())
mangleType(SAE->getArgumentType());
else
mangleTemplateArgExpr(SAE->getArgumentExpr());
Out << 'E';
break;
}
LLVM_FALLTHROUGH;
case UETT_AlignOf:
Out << 'a';
MangleAlignofSizeofArg();
break;
case UETT_VecStep: {
DiagnosticsEngine &Diags = Context.getDiags();
@ -4336,17 +4440,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
return;
}
}
if (SAE->isArgumentType()) {
Out << 't';
mangleType(SAE->getArgumentType());
} else {
Out << 'z';
mangleExpression(SAE->getArgumentExpr());
}
break;
}
case Expr::CXXThrowExprClass: {
NotPrimaryExpr();
const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
// <expression> ::= tw <expression> # throw expression
// ::= tr # rethrow
@ -4360,6 +4458,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXTypeidExprClass: {
NotPrimaryExpr();
const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
// <expression> ::= ti <type> # typeid (type)
// ::= te <expression> # typeid (expression)
@ -4374,6 +4473,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXDeleteExprClass: {
NotPrimaryExpr();
const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
// <expression> ::= [gs] dl <expression> # [::] delete expr
// ::= [gs] da <expression> # [::] delete [] expr
@ -4384,6 +4484,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::UnaryOperatorClass: {
NotPrimaryExpr();
const UnaryOperator *UO = cast<UnaryOperator>(E);
mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
/*Arity=*/1);
@ -4392,6 +4493,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ArraySubscriptExprClass: {
NotPrimaryExpr();
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
// Array subscript is treated as a syntactically weird form of
@ -4403,6 +4505,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::MatrixSubscriptExprClass: {
NotPrimaryExpr();
const MatrixSubscriptExpr *ME = cast<MatrixSubscriptExpr>(E);
Out << "ixix";
mangleExpression(ME->getBase());
@ -4413,6 +4516,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::CompoundAssignOperatorClass: // fallthrough
case Expr::BinaryOperatorClass: {
NotPrimaryExpr();
const BinaryOperator *BO = cast<BinaryOperator>(E);
if (BO->getOpcode() == BO_PtrMemD)
Out << "ds";
@ -4425,6 +4529,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXRewrittenBinaryOperatorClass: {
NotPrimaryExpr();
// The mangled form represents the original syntax.
CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
cast<CXXRewrittenBinaryOperator>(E)->getDecomposedForm();
@ -4436,6 +4541,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ConditionalOperatorClass: {
NotPrimaryExpr();
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
mangleOperatorName(OO_Conditional, /*Arity=*/3);
mangleExpression(CO->getCond());
@ -4451,19 +4557,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ObjCBridgedCastExprClass: {
NotPrimaryExpr();
// Mangle ownership casts as a vendor extended operator __bridge,
// __bridge_transfer, or __bridge_retain.
StringRef Kind = cast<ObjCBridgedCastExpr>(E)->getBridgeKindName();
Out << "v1U" << Kind.size() << Kind;
mangleCastExpression(E, "cv");
break;
}
// Fall through to mangle the cast itself.
LLVM_FALLTHROUGH;
case Expr::CStyleCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "cv");
break;
case Expr::CXXFunctionalCastExprClass: {
NotPrimaryExpr();
auto *Sub = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreImplicit();
// FIXME: Add isImplicit to CXXConstructExpr.
if (auto *CCE = dyn_cast<CXXConstructExpr>(Sub))
@ -4483,22 +4592,28 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXStaticCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "sc");
break;
case Expr::CXXDynamicCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "dc");
break;
case Expr::CXXReinterpretCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "rc");
break;
case Expr::CXXConstCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "cc");
break;
case Expr::CXXAddrspaceCastExprClass:
NotPrimaryExpr();
mangleCastExpression(E, "ac");
break;
case Expr::CXXOperatorCallExprClass: {
NotPrimaryExpr();
const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
unsigned NumArgs = CE->getNumArgs();
// A CXXOperatorCallExpr for OO_Arrow models only semantics, not syntax
@ -4512,9 +4627,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ParenExprClass:
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
break;
E = cast<ParenExpr>(E)->getSubExpr();
goto recurse;
case Expr::ConceptSpecializationExprClass: {
// <expr-primary> ::= L <mangled-name> E # external name
@ -4528,10 +4642,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::DeclRefExprClass:
mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl());
// MangleDeclRefExpr helper handles primary-vs-nonprimary
MangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl());
break;
case Expr::SubstNonTypeTemplateParmPackExprClass:
NotPrimaryExpr();
// FIXME: not clear how to mangle this!
// template <unsigned N...> class A {
// template <class U...> void foo(U (&x)[N]...);
@ -4540,14 +4656,16 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
break;
case Expr::FunctionParmPackExprClass: {
NotPrimaryExpr();
// FIXME: not clear how to mangle this!
const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E);
Out << "v110_SUBSTPACK";
mangleDeclRefExpr(FPPE->getParameterPack());
MangleDeclRefExpr(FPPE->getParameterPack());
break;
}
case Expr::DependentScopeDeclRefExprClass: {
NotPrimaryExpr();
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
mangleUnresolvedName(DRE->getQualifier(), DRE->getDeclName(),
DRE->getTemplateArgs(), DRE->getNumTemplateArgs(),
@ -4556,24 +4674,27 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXBindTemporaryExprClass:
mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
break;
E = cast<CXXBindTemporaryExpr>(E)->getSubExpr();
goto recurse;
case Expr::ExprWithCleanupsClass:
mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity);
break;
E = cast<ExprWithCleanups>(E)->getSubExpr();
goto recurse;
case Expr::FloatingLiteralClass: {
// <expr-primary>
const FloatingLiteral *FL = cast<FloatingLiteral>(E);
mangleFloatLiteral(FL->getType(), FL->getValue());
break;
}
case Expr::FixedPointLiteralClass:
// Currently unimplemented -- might be <expr-primary> in future?
mangleFixedPointLiteral();
break;
case Expr::CharacterLiteralClass:
// <expr-primary>
Out << 'L';
mangleType(E->getType());
Out << cast<CharacterLiteral>(E)->getValue();
@ -4582,18 +4703,21 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
// FIXME. __objc_yes/__objc_no are mangled same as true/false
case Expr::ObjCBoolLiteralExprClass:
// <expr-primary>
Out << "Lb";
Out << (cast<ObjCBoolLiteralExpr>(E)->getValue() ? '1' : '0');
Out << 'E';
break;
case Expr::CXXBoolLiteralExprClass:
// <expr-primary>
Out << "Lb";
Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
Out << 'E';
break;
case Expr::IntegerLiteralClass: {
// <expr-primary>
llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue());
if (E->getType()->isSignedIntegerType())
Value.setIsSigned(true);
@ -4602,6 +4726,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::ImaginaryLiteralClass: {
// <expr-primary>
const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E);
// Mangle as if a complex literal.
// Proposal from David Vandevoorde, 2010.06.30.
@ -4625,6 +4750,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::StringLiteralClass: {
// <expr-primary>
// Revised proposal from David Vandervoorde, 2010.07.15.
Out << 'L';
assert(isa<ConstantArrayType>(E->getType()));
@ -4634,21 +4760,25 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::GNUNullExprClass:
// <expr-primary>
// Mangle as if an integer literal 0.
mangleIntegerLiteral(E->getType(), llvm::APSInt(32));
break;
case Expr::CXXNullPtrLiteralExprClass: {
// <expr-primary>
Out << "LDnE";
break;
}
case Expr::PackExpansionExprClass:
NotPrimaryExpr();
Out << "sp";
mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
break;
case Expr::SizeOfPackExprClass: {
NotPrimaryExpr();
auto *SPE = cast<SizeOfPackExpr>(E);
if (SPE->isPartiallySubstituted()) {
Out << "sP";
@ -4673,12 +4803,12 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
break;
}
case Expr::MaterializeTemporaryExprClass: {
mangleExpression(cast<MaterializeTemporaryExpr>(E)->getSubExpr());
break;
}
case Expr::MaterializeTemporaryExprClass:
E = cast<MaterializeTemporaryExpr>(E)->getSubExpr();
goto recurse;
case Expr::CXXFoldExprClass: {
NotPrimaryExpr();
auto *FE = cast<CXXFoldExpr>(E);
if (FE->isLeftFold())
Out << (FE->getInit() ? "fL" : "fl");
@ -4700,27 +4830,34 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
}
case Expr::CXXThisExprClass:
NotPrimaryExpr();
Out << "fpT";
break;
case Expr::CoawaitExprClass:
// FIXME: Propose a non-vendor mangling.
NotPrimaryExpr();
Out << "v18co_await";
mangleExpression(cast<CoawaitExpr>(E)->getOperand());
break;
case Expr::DependentCoawaitExprClass:
// FIXME: Propose a non-vendor mangling.
NotPrimaryExpr();
Out << "v18co_await";
mangleExpression(cast<DependentCoawaitExpr>(E)->getOperand());
break;
case Expr::CoyieldExprClass:
// FIXME: Propose a non-vendor mangling.
NotPrimaryExpr();
Out << "v18co_yield";
mangleExpression(cast<CoawaitExpr>(E)->getOperand());
break;
}
if (AsTemplateArg && !IsPrimaryExpr)
Out << 'E';
}
/// Mangle an expression which refers to a parameter variable.
@ -4970,26 +5107,9 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
Out << "Dp";
mangleType(A.getAsTemplateOrTemplatePattern());
break;
case TemplateArgument::Expression: {
// It's possible to end up with a DeclRefExpr here in certain
// dependent cases, in which case we should mangle as a
// declaration.
const Expr *E = A.getAsExpr()->IgnoreParenImpCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const ValueDecl *D = DRE->getDecl();
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
Out << 'L';
mangle(D);
Out << 'E';
break;
}
}
Out << 'X';
mangleExpression(E);
Out << 'E';
case TemplateArgument::Expression:
mangleTemplateArgExpr(A.getAsExpr());
break;
}
case TemplateArgument::Integral:
mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral());
break;
@ -5044,6 +5164,38 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
}
}
void CXXNameMangler::mangleTemplateArgExpr(const Expr *E) {
ASTContext &Ctx = Context.getASTContext();
if (Ctx.getLangOpts().getClangABICompat() > LangOptions::ClangABI::Ver11) {
mangleExpression(E, UnknownArity, /*AsTemplateArg=*/true);
return;
}
// Prior to Clang 12, we didn't omit the X .. E around <expr-primary>
// correctly in cases where the template argument was
// constructed from an expression rather than an already-evaluated
// literal. In such a case, we would then e.g. emit 'XLi0EE' instead of
// 'Li0E'.
//
// We did special-case DeclRefExpr to attempt to DTRT for that one
// expression-kind, but while doing so, unfortunately handled ParmVarDecl
// (subtype of VarDecl) _incorrectly_, and emitted 'L_Z .. E' instead of
// the proper 'Xfp_E'.
E = E->IgnoreParenImpCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const ValueDecl *D = DRE->getDecl();
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {
Out << 'L';
mangle(D);
Out << 'E';
return;
}
}
Out << 'X';
mangleExpression(E);
Out << 'E';
}
/// Determine whether a given value is equivalent to zero-initialization for
/// the purpose of discarding a trailing portion of a 'tl' mangling.
///

View File

@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
@ -64,6 +65,19 @@ class MicrosoftNumberingContext : public MangleNumberingContext {
}
};
class MSHIPNumberingContext : public MicrosoftNumberingContext {
std::unique_ptr<MangleNumberingContext> DeviceCtx;
public:
MSHIPNumberingContext(MangleContext *DeviceMangler) {
DeviceCtx = createItaniumNumberingContext(DeviceMangler);
}
unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override {
return DeviceCtx->getManglingNumber(CallOperator);
}
};
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
@ -73,8 +87,20 @@ class MicrosoftCXXABI : public CXXABI {
llvm::SmallDenseMap<TagDecl *, TypedefNameDecl *>
UnnamedTagDeclToTypedefNameDecl;
// MangleContext for device numbering context, which is based on Itanium C++
// ABI.
std::unique_ptr<MangleContext> DeviceMangler;
public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) {
if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {
assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&
Context.getAuxTargetInfo()->getCXXABI().isItaniumFamily() &&
"Unexpected combination of C++ ABIs.");
DeviceMangler.reset(
Context.createMangleContext(Context.getAuxTargetInfo()));
}
}
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override;
@ -133,6 +159,10 @@ class MicrosoftCXXABI : public CXXABI {
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) {
assert(DeviceMangler && "Missing device mangler");
return std::make_unique<MSHIPNumberingContext>(DeviceMangler.get());
}
return std::make_unique<MicrosoftNumberingContext>();
}
};
@ -266,4 +296,3 @@ CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
return new MicrosoftCXXABI(Ctx);
}

View File

@ -243,10 +243,14 @@ class MatchChildASTVisitor
return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
if (auto *Init = Node->getInit())
if (!match(*Init))
if (!traverse(*Init))
return false;
if (!match(*Node->getLoopVariable()) || !match(*Node->getRangeInit()) ||
!match(*Node->getBody()))
if (!match(*Node->getLoopVariable()))
return false;
if (match(*Node->getRangeInit()))
if (!VisitorBase::TraverseStmt(Node->getRangeInit()))
return false;
if (!match(*Node->getBody()))
return false;
return VisitorBase::TraverseStmt(Node->getBody());
}
@ -291,7 +295,7 @@ class MatchChildASTVisitor
if (!match(*Node->getBody()))
return false;
return true;
return VisitorBase::TraverseStmt(Node->getBody());
}
bool shouldVisitTemplateInstantiations() const { return true; }
@ -488,15 +492,21 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) {
if (auto *RF = dyn_cast<CXXForRangeStmt>(S)) {
for (auto *SubStmt : RF->children()) {
if (SubStmt == RF->getInit() || SubStmt == RF->getLoopVarStmt() ||
SubStmt == RF->getRangeInit() || SubStmt == RF->getBody()) {
TraverseStmt(SubStmt, Queue);
} else {
ASTNodeNotSpelledInSourceScope RAII(this, true);
TraverseStmt(SubStmt, Queue);
{
ASTNodeNotAsIsSourceScope RAII(this, true);
TraverseStmt(RF->getInit());
// Don't traverse under the loop variable
match(*RF->getLoopVariable());
TraverseStmt(RF->getRangeInit());
}
{
ASTNodeNotSpelledInSourceScope RAII(this, true);
for (auto *SubStmt : RF->children()) {
if (SubStmt != RF->getBody())
TraverseStmt(SubStmt);
}
}
TraverseStmt(RF->getBody());
return true;
} else if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
{
@ -556,9 +566,9 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
if (LE->hasExplicitResultType())
TraverseTypeLoc(Proto.getReturnLoc());
TraverseStmt(LE->getTrailingRequiresClause());
TraverseStmt(LE->getBody());
}
TraverseStmt(LE->getBody());
return true;
}
return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
@ -697,6 +707,10 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
// We visit the lambda body explicitly, so instruct the RAV
// to not visit it on our behalf too.
bool shouldVisitLambdaBody() const { return false; }
bool IsMatchingInASTNodeNotSpelledInSource() const override {
return TraversingASTNodeNotSpelledInSource;
}
@ -823,6 +837,14 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
if (EnableCheckProfiling)
Timer.setBucket(&TimeByBucket[MP.second->getID()]);
BoundNodesTreeBuilder Builder;
{
TraversalKindScope RAII(getASTContext(), MP.first.getTraversalKind());
if (getASTContext().getParentMapContext().traverseIgnored(DynNode) !=
DynNode)
continue;
}
if (MP.first.matches(DynNode, this, &Builder)) {
MatchVisitor Visitor(ActiveASTContext, MP.second);
Builder.visitMatches(&Visitor);

View File

@ -732,7 +732,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasTemplateDecl>
typeAliasTemplateDecl;
const internal::VariadicAllOfMatcher<Decl> decl;
const internal::VariadicAllOfMatcher<DecompositionDecl> decompositionDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, DecompositionDecl> decompositionDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl>
linkageSpecDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl;

View File

@ -82,6 +82,7 @@ static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
case CodeGenOptions::ProfileCSIRInstr:
return "csllvm";
}
llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
}
llvm::Optional<bool>

View File

@ -318,9 +318,6 @@ bool PPCTargetInfo::initFeatureMap(
.Case("pwr9", true)
.Case("pwr8", true)
.Default(false);
Features["float128"] = llvm::StringSwitch<bool>(CPU)
.Case("pwr9", true)
.Default(false);
Features["spe"] = llvm::StringSwitch<bool>(CPU)
.Case("8548", true)

View File

@ -150,7 +150,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
}
if (HasV) {
Builder.defineMacro("__riscv_v", "1000000");
Builder.defineMacro("__riscv_v", "10000");
Builder.defineMacro("__riscv_vector");
}
@ -191,10 +191,10 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv_zfh", "1000");
if (HasZvamo)
Builder.defineMacro("__riscv_zvamo", "1000000");
Builder.defineMacro("__riscv_zvamo", "10000");
if (HasZvlsseg)
Builder.defineMacro("__riscv_zvlsseg", "1000000");
Builder.defineMacro("__riscv_zvlsseg", "10000");
}
/// Return true if has this feature, need to sync with handleTargetFeatures.

View File

@ -13794,12 +13794,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_reduce_fadd_ps512: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fadd, Ops[1]->getType());
Builder.getFastMathFlags().setAllowReassoc(true);
return Builder.CreateCall(F, {Ops[0], Ops[1]});
}
case X86::BI__builtin_ia32_reduce_fmul_pd512:
case X86::BI__builtin_ia32_reduce_fmul_ps512: {
Function *F =
CGM.getIntrinsic(Intrinsic::vector_reduce_fmul, Ops[1]->getType());
Builder.getFastMathFlags().setAllowReassoc(true);
return Builder.CreateCall(F, {Ops[0], Ops[1]});
}
case X86::BI__builtin_ia32_reduce_mul_d512:

View File

@ -184,6 +184,14 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy));
VoidPtrTy = cast<llvm::PointerType>(Types.ConvertType(Ctx.VoidPtrTy));
VoidPtrPtrTy = VoidPtrTy->getPointerTo();
if (CGM.getContext().getAuxTargetInfo()) {
// If the host and device have different C++ ABIs, mark it as the device
// mangle context so that the mangling needs to retrieve the additonal
// device lambda mangling number instead of the regular host one.
DeviceMC->setDeviceMangleContext(
CGM.getContext().getTargetInfo().getCXXABI().isMicrosoft() &&
CGM.getContext().getAuxTargetInfo()->getCXXABI().isItaniumFamily());
}
}
llvm::FunctionCallee CGNVCUDARuntime::getSetupArgumentFn() const {

View File

@ -1995,9 +1995,14 @@ void CodeGenModule::ConstructAttributeList(
if (TargetDecl->hasAttr<ConstAttr>()) {
FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
// gcc specifies that 'const' functions have greater restrictions than
// 'pure' functions, so they also cannot have infinite loops.
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
} else if (TargetDecl->hasAttr<PureAttr>()) {
FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
// gcc specifies that 'pure' functions cannot have infinite loops.
FuncAttrs.addAttribute(llvm::Attribute::WillReturn);
} else if (TargetDecl->hasAttr<NoAliasAttr>()) {
FuncAttrs.addAttribute(llvm::Attribute::ArgMemOnly);
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);

View File

@ -1622,8 +1622,8 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
if (CD->isTrivial() && CD->isDefaultConstructor())
return CGM.EmitNullConstant(D.getType());
}
InConstantContext = true;
}
InConstantContext = D.hasConstantInitialization();
QualType destType = D.getType();

View File

@ -409,6 +409,7 @@ class InlinedOpenMPRegionRAII {
llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField = nullptr;
const CodeGen::CGBlockInfo *BlockInfo = nullptr;
bool NoInheritance = false;
public:
/// Constructs region for combined constructs.
@ -416,16 +417,19 @@ class InlinedOpenMPRegionRAII {
/// a list of functions used for code generation of implicitly inlined
/// regions.
InlinedOpenMPRegionRAII(CodeGenFunction &CGF, const RegionCodeGenTy &CodeGen,
OpenMPDirectiveKind Kind, bool HasCancel)
: CGF(CGF) {
OpenMPDirectiveKind Kind, bool HasCancel,
bool NoInheritance = true)
: CGF(CGF), NoInheritance(NoInheritance) {
// Start emission for the construct.
CGF.CapturedStmtInfo = new CGOpenMPInlinedRegionInfo(
CGF.CapturedStmtInfo, CodeGen, Kind, HasCancel);
std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
LambdaThisCaptureField = CGF.LambdaThisCaptureField;
CGF.LambdaThisCaptureField = nullptr;
BlockInfo = CGF.BlockInfo;
CGF.BlockInfo = nullptr;
if (NoInheritance) {
std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
LambdaThisCaptureField = CGF.LambdaThisCaptureField;
CGF.LambdaThisCaptureField = nullptr;
BlockInfo = CGF.BlockInfo;
CGF.BlockInfo = nullptr;
}
}
~InlinedOpenMPRegionRAII() {
@ -434,9 +438,11 @@ class InlinedOpenMPRegionRAII {
cast<CGOpenMPInlinedRegionInfo>(CGF.CapturedStmtInfo)->getOldCSI();
delete CGF.CapturedStmtInfo;
CGF.CapturedStmtInfo = OldCSI;
std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
CGF.LambdaThisCaptureField = LambdaThisCaptureField;
CGF.BlockInfo = BlockInfo;
if (NoInheritance) {
std::swap(CGF.LambdaCaptureFields, LambdaCaptureFields);
CGF.LambdaThisCaptureField = LambdaThisCaptureField;
CGF.BlockInfo = BlockInfo;
}
}
};
@ -3853,7 +3859,7 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
// Processing for implicitly captured variables.
InlinedOpenMPRegionRAII Region(
CGF, [](CodeGenFunction &, PrePostActionTy &) {}, OMPD_unknown,
/*HasCancel=*/false);
/*HasCancel=*/false, /*NoInheritance=*/true);
SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef);
}
if (Type->isArrayType()) {
@ -6214,7 +6220,9 @@ void CGOpenMPRuntime::emitInlinedDirective(CodeGenFunction &CGF,
bool HasCancel) {
if (!CGF.HaveInsertPoint())
return;
InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel);
InlinedOpenMPRegionRAII Region(CGF, CodeGen, InnerKind, HasCancel,
InnerKind != OMPD_critical &&
InnerKind != OMPD_master);
CGF.CapturedStmtInfo->EmitBody(CGF, /*S=*/nullptr);
}
@ -9892,7 +9900,7 @@ void CGOpenMPRuntime::emitTargetNumIterationsCall(
llvm::Value *Args[] = {RTLoc, DeviceID, NumIterations};
CGF.EmitRuntimeCall(
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_push_target_tripcount),
CGM.getModule(), OMPRTL___kmpc_push_target_tripcount_mapper),
Args);
}
};

View File

@ -507,12 +507,23 @@ class CodeGenFunction : public CodeGenTypeCache {
/// True if the C++ Standard Requires Progress.
bool CPlusPlusWithProgress() {
if (CGM.getCodeGenOpts().getFiniteLoops() ==
CodeGenOptions::FiniteLoopsKind::Never)
return false;
return getLangOpts().CPlusPlus11 || getLangOpts().CPlusPlus14 ||
getLangOpts().CPlusPlus17 || getLangOpts().CPlusPlus20;
}
/// True if the C Standard Requires Progress.
bool CWithProgress() {
if (CGM.getCodeGenOpts().getFiniteLoops() ==
CodeGenOptions::FiniteLoopsKind::Always)
return true;
if (CGM.getCodeGenOpts().getFiniteLoops() ==
CodeGenOptions::FiniteLoopsKind::Never)
return false;
return getLangOpts().C11 || getLangOpts().C17 || getLangOpts().C2x;
}

View File

@ -63,7 +63,7 @@ isExperimentalExtension(StringRef Ext) {
Ext == "zbr" || Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc")
return RISCVExtensionVersion{"0", "93"};
if (Ext == "v" || Ext == "zvamo" || Ext == "zvlsseg")
return RISCVExtensionVersion{"1", "0"};
return RISCVExtensionVersion{"0", "10"};
if (Ext == "zfh")
return RISCVExtensionVersion{"0", "1"};
return None;

View File

@ -4669,20 +4669,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
}
if (Triple.isOSAIX() && Args.hasArg(options::OPT_maltivec)) {
if (Args.getLastArg(options::OPT_mabi_EQ_vec_extabi)) {
CmdArgs.push_back("-mabi=vec-extabi");
} else {
D.Diag(diag::err_aix_default_altivec_abi);
}
}
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_vec_extabi,
options::OPT_mabi_EQ_vec_default)) {
if (!Triple.isOSAIX())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
if (A->getOption().getID() == options::OPT_mabi_EQ_vec_default)
if (A->getOption().getID() == options::OPT_mabi_EQ_vec_extabi)
CmdArgs.push_back("-mabi=vec-extabi");
else
D.Diag(diag::err_aix_default_altivec_abi);
}
@ -5626,6 +5620,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (A->getOption().matches(options::OPT_freroll_loops))
CmdArgs.push_back("-freroll-loops");
Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
options::OPT_fno_finite_loops);
Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings);
Args.AddLastArg(CmdArgs, options::OPT_funroll_loops,
options::OPT_fno_unroll_loops);

View File

@ -605,6 +605,11 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
CmdArgs.push_back("-plugin-opt=new-pass-manager");
}
// Pass an option to enable pseudo probe emission.
if (Args.hasFlag(options::OPT_fpseudo_probe_for_profiling,
options::OPT_fno_pseudo_probe_for_profiling, false))
CmdArgs.push_back("-plugin-opt=pseudo-probe-for-profiling");
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty())

View File

@ -236,15 +236,6 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
ExtraOpts.push_back("relro");
}
if (Triple.isAndroid() && Triple.isAndroidVersionLT(29)) {
// https://github.com/android/ndk/issues/1196
// The unwinder used by the crash handler on versions of Android prior to
// API 29 did not correctly handle binaries built with rosegment, which is
// enabled by default for LLD. Android only supports LLD, so it's not an
// issue that this flag is not accepted by other linkers.
ExtraOpts.push_back("--no-rosegment");
}
// Android ARM/AArch64 use max-page-size=4096 to reduce VMA usage. Note, lld
// from 11 onwards default max-page-size to 65536 for both ARM and AArch64.
if ((Triple.isARM() || Triple.isAArch64()) && Triple.isAndroid()) {

View File

@ -11,6 +11,7 @@
#include "Darwin.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
@ -520,7 +521,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// translate 'lld' into 'lld-link', and in the case of the regular msvc
// linker, we need to use a special search algorithm.
llvm::SmallString<128> linkPath;
StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link");
StringRef Linker
= Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER);
if (Linker.empty())
Linker = "link";
if (Linker.equals_lower("lld"))
Linker = "lld-link";

View File

@ -296,6 +296,7 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args,
CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi");
CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread");
}
std::string OpenBSD::getCompilerRT(const ArgList &Args,

View File

@ -371,7 +371,7 @@ class LineJoiner {
if (Previous->is(tok::comment))
Previous = Previous->getPreviousNonComment();
if (Previous) {
if (Previous->is(tok::greater))
if (Previous->is(tok::greater) && !I[-1]->InPPDirective)
return 0;
if (Previous->is(tok::identifier)) {
const FormatToken *PreviousPrevious =

View File

@ -1037,7 +1037,6 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.UnrollLoops =
Args.hasFlag(OPT_funroll_loops, OPT_fno_unroll_loops,
(Opts.OptimizationLevel > 1));
Opts.BinutilsVersion =
std::string(Args.getLastArgValue(OPT_fbinutils_version_EQ));
@ -1324,6 +1323,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
if (Args.hasArg(options::OPT_ffinite_loops))
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
else if (Args.hasArg(options::OPT_fno_finite_loops))
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Never;
return Success;
}
@ -2470,6 +2473,8 @@ void CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
bool IsTargetSpecified =
Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ);
Opts.ConvergentFunctions = Opts.ConvergentFunctions || Opts.OpenMPIsDevice;
if (Opts.OpenMP || Opts.OpenMPSimd) {
if (int Version = getLastArgIntValue(
Args, OPT_fopenmp_version_EQ,

View File

@ -565,7 +565,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_aggregate_bases", "201603L");
Builder.defineMacro("__cpp_structured_bindings", "201606L");
Builder.defineMacro("__cpp_nontype_template_args",
LangOpts.CPlusPlus20 ? "201911L" : "201411L");
"201411L"); // (not latest)
Builder.defineMacro("__cpp_fold_expressions", "201603L");
Builder.defineMacro("__cpp_guaranteed_copy_elision", "201606L");
Builder.defineMacro("__cpp_nontype_template_parameter_auto", "201606L");

View File

@ -9297,9 +9297,12 @@ _mm512_mask_abs_pd(__m512d __W, __mmask8 __K, __m512d __A)
/* Vector-reduction arithmetic accepts vectors as inputs and produces scalars as
* outputs. This class of vector operation forms the basis of many scientific
* computations. In vector-reduction arithmetic, the evaluation off is
* computations. In vector-reduction arithmetic, the evaluation order is
* independent of the order of the input elements of V.
* For floating point types, we always assume the elements are reassociable even
* if -fast-math is off.
* Used bisection method. At each step, we partition the vector with previous
* step in half, and the operation is performed on its two halves.
* This takes log2(n) steps where n is the number of elements in the vector.
@ -9345,8 +9348,11 @@ _mm512_mask_reduce_or_epi64(__mmask8 __M, __m512i __W) {
return __builtin_ia32_reduce_or_q512(__W);
}
// -0.0 is used to ignore the start value since it is the neutral value of
// floating point addition. For more information, please refer to
// https://llvm.org/docs/LangRef.html#llvm-vector-reduce-fadd-intrinsic
static __inline__ double __DEFAULT_FN_ATTRS512 _mm512_reduce_add_pd(__m512d __W) {
return __builtin_ia32_reduce_fadd_pd512(0.0, __W);
return __builtin_ia32_reduce_fadd_pd512(-0.0, __W);
}
static __inline__ double __DEFAULT_FN_ATTRS512 _mm512_reduce_mul_pd(__m512d __W) {
@ -9356,7 +9362,7 @@ static __inline__ double __DEFAULT_FN_ATTRS512 _mm512_reduce_mul_pd(__m512d __W)
static __inline__ double __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_add_pd(__mmask8 __M, __m512d __W) {
__W = _mm512_maskz_mov_pd(__M, __W);
return __builtin_ia32_reduce_fadd_pd512(0.0, __W);
return __builtin_ia32_reduce_fadd_pd512(-0.0, __W);
}
static __inline__ double __DEFAULT_FN_ATTRS512
@ -9411,7 +9417,7 @@ _mm512_mask_reduce_or_epi32(__mmask16 __M, __m512i __W) {
static __inline__ float __DEFAULT_FN_ATTRS512
_mm512_reduce_add_ps(__m512 __W) {
return __builtin_ia32_reduce_fadd_ps512(0.0f, __W);
return __builtin_ia32_reduce_fadd_ps512(-0.0f, __W);
}
static __inline__ float __DEFAULT_FN_ATTRS512
@ -9422,7 +9428,7 @@ _mm512_reduce_mul_ps(__m512 __W) {
static __inline__ float __DEFAULT_FN_ATTRS512
_mm512_mask_reduce_add_ps(__mmask16 __M, __m512 __W) {
__W = _mm512_maskz_mov_ps(__M, __W);
return __builtin_ia32_reduce_fadd_ps512(0.0f, __W);
return __builtin_ia32_reduce_fadd_ps512(-0.0f, __W);
}
static __inline__ float __DEFAULT_FN_ATTRS512

View File

@ -119,12 +119,8 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
// a macro. They get unpoisoned where it is allowed.
(Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
if (getLangOpts().CPlusPlus20) {
(Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use);
} else {
Ident__VA_OPT__ = nullptr;
}
(Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned();
SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use);
// Initialize the pragma handlers.
RegisterBuiltinPragmas();

View File

@ -148,12 +148,12 @@ bool TokenLexer::MaybeRemoveCommaBeforeVaArgs(
return false;
// GCC removes the comma in the expansion of " ... , ## __VA_ARGS__ " if
// __VA_ARGS__ is empty, but not in strict mode where there are no
// named arguments, where it remains. With GNU extensions, it is removed
// regardless of named arguments.
// __VA_ARGS__ is empty, but not in strict C99 mode where there are no
// named arguments, where it remains. In all other modes, including C99
// with GNU extensions, it is removed regardless of named arguments.
// Microsoft also appears to support this extension, unofficially.
if (!PP.getLangOpts().GNUMode && !PP.getLangOpts().MSVCCompat &&
Macro->getNumParams() < 2)
if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode
&& Macro->getNumParams() < 2)
return false;
// Is a comma available to be removed?

View File

@ -4216,7 +4216,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
// Parse _Static_assert declaration.
if (Tok.is(tok::kw__Static_assert)) {
if (Tok.isOneOf(tok::kw__Static_assert, tok::kw_static_assert)) {
SourceLocation DeclEnd;
ParseStaticAssertDeclaration(DeclEnd);
continue;
@ -5180,6 +5180,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_friend:
// static_assert-declaration
case tok::kw_static_assert:
case tok::kw__Static_assert:
// GNU typeof support.

View File

@ -14,6 +14,7 @@
#include "UsedDeclVisitor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
@ -537,6 +538,13 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) {
if (E->IgnoreParenImpCasts()->getType()->isNullPtrType())
return;
// Don't diagnose the conversion from a 0 literal to a null pointer argument
// in a synthesized call to operator<=>.
if (!CodeSynthesisContexts.empty() &&
CodeSynthesisContexts.back().Kind ==
CodeSynthesisContext::RewritingOperatorAsSpaceship)
return;
// If it is a macro from system header, and if the macro name is not "NULL",
// do not warn.
SourceLocation MaybeMacroLoc = E->getBeginLoc();
@ -1733,11 +1741,12 @@ Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
}
}
Sema::SemaDiagnosticBuilder Sema::targetDiag(SourceLocation Loc,
unsigned DiagID) {
Sema::SemaDiagnosticBuilder
Sema::targetDiag(SourceLocation Loc, unsigned DiagID, FunctionDecl *FD) {
FD = FD ? FD : getCurFunctionDecl();
if (LangOpts.OpenMP)
return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
: diagIfOpenMPHostCode(Loc, DiagID);
return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID, FD)
: diagIfOpenMPHostCode(Loc, DiagID, FD);
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
@ -1746,7 +1755,7 @@ Sema::SemaDiagnosticBuilder Sema::targetDiag(SourceLocation Loc,
return SYCLDiagIfDeviceCode(Loc, DiagID);
return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, DiagID,
getCurFunctionDecl(), *this);
FD, *this);
}
Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID,
@ -1765,15 +1774,14 @@ Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID,
DiagID, getCurFunctionDecl(), *this);
}
SemaDiagnosticBuilder DB =
getLangOpts().CUDAIsDevice
? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice
? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
SetIsLastErrorImmediate(DB.isImmediate());
return DB;
}
void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
void Sema::checkDeviceDecl(ValueDecl *D, SourceLocation Loc) {
if (isUnevaluatedContext())
return;
@ -1791,13 +1799,17 @@ void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
return;
}
// Try to associate errors with the lexical context, if that is a function, or
// the value declaration otherwise.
FunctionDecl *FD =
isa<FunctionDecl>(C) ? cast<FunctionDecl>(C) : dyn_cast<FunctionDecl>(D);
auto CheckType = [&](QualType Ty) {
if (Ty->isDependentType())
return;
if (Ty->isExtIntType()) {
if (!Context.getTargetInfo().hasExtIntType()) {
targetDiag(Loc, diag::err_device_unsupported_type)
targetDiag(Loc, diag::err_device_unsupported_type, FD)
<< D << false /*show bit size*/ << 0 /*bitsize*/
<< Ty << Context.getTargetInfo().getTriple().str();
}
@ -1810,11 +1822,12 @@ void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
!Context.getTargetInfo().hasFloat128Type()) ||
(Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
!Context.getTargetInfo().hasInt128Type())) {
targetDiag(Loc, diag::err_device_unsupported_type)
if (targetDiag(Loc, diag::err_device_unsupported_type, FD)
<< D << true /*show bit size*/
<< static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
<< Context.getTargetInfo().getTriple().str();
targetDiag(D->getLocation(), diag::note_defined_here) << D;
<< Context.getTargetInfo().getTriple().str())
D->setInvalidDecl();
targetDiag(D->getLocation(), diag::note_defined_here, FD) << D;
}
};
@ -1826,6 +1839,8 @@ void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) {
CheckType(ParamTy);
CheckType(FPTy->getReturnType());
}
if (const auto *FNPTy = dyn_cast<FunctionNoProtoType>(Ty))
CheckType(FNPTy->getReturnType());
}
/// Looks through the macro-expansion chain for the given

View File

@ -5158,6 +5158,20 @@ class ConceptInfo {
llvm::DenseMap<const IdentifierInfo *, Member> Results;
};
// If \p Base is ParenListExpr, assume a chain of comma operators and pick the
// last expr. We expect other ParenListExprs to be resolved to e.g. constructor
// calls before here. (So the ParenListExpr should be nonempty, but check just
// in case)
Expr *unwrapParenList(Expr *Base) {
if (auto *PLE = llvm::dyn_cast_or_null<ParenListExpr>(Base)) {
if (PLE->getNumExprs() == 0)
return nullptr;
Base = PLE->getExpr(PLE->getNumExprs() - 1);
}
return Base;
}
} // namespace
void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
@ -5165,6 +5179,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base,
SourceLocation OpLoc, bool IsArrow,
bool IsBaseExprStatement,
QualType PreferredType) {
Base = unwrapParenList(Base);
OtherOpBase = unwrapParenList(OtherOpBase);
if (!Base || !CodeCompleter)
return;
@ -5597,12 +5613,13 @@ ProduceSignatureHelp(Sema &SemaRef, Scope *S,
QualType Sema::ProduceCallSignatureHelp(Scope *S, Expr *Fn,
ArrayRef<Expr *> Args,
SourceLocation OpenParLoc) {
if (!CodeCompleter)
Fn = unwrapParenList(Fn);
if (!CodeCompleter || !Fn)
return QualType();
// FIXME: Provide support for variadic template functions.
// Ignore type-dependent call expressions entirely.
if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args))
if (Fn->isTypeDependent() || anyNullArguments(Args))
return QualType();
// In presence of dependent args we surface all possible signatures using the
// non-dependent args in the prefix. Afterwards we do a post filtering to make

View File

@ -9420,6 +9420,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice))
checkDeviceDecl(NewFD, D.getBeginLoc());
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
if (!NewFD->isInvalidDecl() && NewFD->isMain())
@ -18329,42 +18332,51 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
if (FD->isDependentContext())
return FunctionEmissionStatus::TemplateDiscarded;
FunctionEmissionStatus OMPES = FunctionEmissionStatus::Unknown;
// Check whether this function is an externally visible definition.
auto IsEmittedForExternalSymbol = [this, FD]() {
// We have to check the GVA linkage of the function's *definition* -- if we
// only have a declaration, we don't know whether or not the function will
// be emitted, because (say) the definition could include "inline".
FunctionDecl *Def = FD->getDefinition();
return Def && !isDiscardableGVALinkage(
getASTContext().GetGVALinkageForFunction(Def));
};
if (LangOpts.OpenMPIsDevice) {
// In OpenMP device mode we will not emit host only functions, or functions
// we don't need due to their linkage.
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
if (DevTy.hasValue()) {
// DevTy may be changed later by
// #pragma omp declare target to(*) device_type(*).
// Therefore DevTyhaving no value does not imply host. The emission status
// will be checked again at the end of compilation unit with Final = true.
if (DevTy.hasValue())
if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
OMPES = FunctionEmissionStatus::OMPDiscarded;
else if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost ||
*DevTy == OMPDeclareTargetDeclAttr::DT_Any) {
OMPES = FunctionEmissionStatus::Emitted;
}
}
} else if (LangOpts.OpenMP) {
// In OpenMP 4.5 all the functions are host functions.
if (LangOpts.OpenMP <= 45) {
OMPES = FunctionEmissionStatus::Emitted;
} else {
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
// In OpenMP 5.0 or above, DevTy may be changed later by
// #pragma omp declare target to(*) device_type(*). Therefore DevTy
// having no value does not imply host. The emission status will be
// checked again at the end of compilation unit.
if (DevTy.hasValue()) {
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
OMPES = FunctionEmissionStatus::OMPDiscarded;
} else if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host ||
*DevTy == OMPDeclareTargetDeclAttr::DT_Any)
OMPES = FunctionEmissionStatus::Emitted;
} else if (Final)
OMPES = FunctionEmissionStatus::Emitted;
}
return FunctionEmissionStatus::OMPDiscarded;
// If we have an explicit value for the device type, or we are in a target
// declare context, we need to emit all extern and used symbols.
if (isInOpenMPDeclareTargetContext() || DevTy.hasValue())
if (IsEmittedForExternalSymbol())
return FunctionEmissionStatus::Emitted;
// Device mode only emits what it must, if it wasn't tagged yet and needed,
// we'll omit it.
if (Final)
return FunctionEmissionStatus::OMPDiscarded;
} else if (LangOpts.OpenMP > 45) {
// In OpenMP host compilation prior to 5.0 everything was an emitted host
// function. In 5.0, no_host was introduced which might cause a function to
// be ommitted.
Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
if (DevTy.hasValue())
if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
return FunctionEmissionStatus::OMPDiscarded;
}
if (OMPES == FunctionEmissionStatus::OMPDiscarded ||
(OMPES == FunctionEmissionStatus::Emitted && !LangOpts.CUDA))
return OMPES;
if (Final && LangOpts.OpenMP && !LangOpts.CUDA)
return FunctionEmissionStatus::Emitted;
if (LangOpts.CUDA) {
// When compiling for device, host functions are never emitted. Similarly,
@ -18378,17 +18390,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD,
(T == Sema::CFT_Device || T == Sema::CFT_Global))
return FunctionEmissionStatus::CUDADiscarded;
// Check whether this function is externally visible -- if so, it's
// known-emitted.
//
// We have to check the GVA linkage of the function's *definition* -- if we
// only have a declaration, we don't know whether or not the function will
// be emitted, because (say) the definition could include "inline".
FunctionDecl *Def = FD->getDefinition();
if (Def &&
!isDiscardableGVALinkage(getASTContext().GetGVALinkageForFunction(Def))
&& (!LangOpts.OpenMP || OMPES == FunctionEmissionStatus::Emitted))
if (IsEmittedForExternalSymbol())
return FunctionEmissionStatus::Emitted;
}

View File

@ -373,7 +373,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
}
if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) {
if (const auto *VD = dyn_cast<ValueDecl>(D))
if (auto *VD = dyn_cast<ValueDecl>(D))
checkDeviceDecl(VD, Loc);
if (!Context.getTargetInfo().isTLSSupported())

View File

@ -432,15 +432,16 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
void Sema::handleLambdaNumbering(
CXXRecordDecl *Class, CXXMethodDecl *Method,
Optional<std::tuple<unsigned, bool, Decl *>> Mangling) {
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) {
if (Mangling) {
unsigned ManglingNumber;
bool HasKnownInternalLinkage;
unsigned ManglingNumber, DeviceManglingNumber;
Decl *ManglingContextDecl;
std::tie(ManglingNumber, HasKnownInternalLinkage, ManglingContextDecl) =
Mangling.getValue();
std::tie(HasKnownInternalLinkage, ManglingNumber, DeviceManglingNumber,
ManglingContextDecl) = Mangling.getValue();
Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
HasKnownInternalLinkage);
Class->setDeviceLambdaManglingNumber(DeviceManglingNumber);
return;
}
@ -476,6 +477,7 @@ void Sema::handleLambdaNumbering(
unsigned ManglingNumber = MCtx->getManglingNumber(Method);
Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
HasKnownInternalLinkage);
Class->setDeviceLambdaManglingNumber(MCtx->getDeviceManglingNumber(Method));
}
}

View File

@ -1884,8 +1884,7 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
static bool isOpenMPDeviceDelayedContext(Sema &S) {
assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
return !S.isInOpenMPTargetExecutionDirective() &&
!S.isInOpenMPDeclareTargetContext();
return !S.isInOpenMPTargetExecutionDirective();
}
namespace {
@ -1898,11 +1897,11 @@ enum class FunctionEmissionStatus {
} // anonymous namespace
Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
unsigned DiagID,
FunctionDecl *FD) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
FunctionDecl *FD = getCurFunctionDecl();
SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop;
if (FD) {
FunctionEmissionStatus FES = getEmissionStatus(FD);
@ -1911,6 +1910,13 @@ Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
Kind = SemaDiagnosticBuilder::K_Immediate;
break;
case FunctionEmissionStatus::Unknown:
// TODO: We should always delay diagnostics here in case a target
// region is in a function we do not emit. However, as the
// current diagnostics are associated with the function containing
// the target region and we do not emit that one, we would miss out
// on diagnostics for the target region itself. We need to anchor
// the diagnostics with the new generated function *or* ensure we
// emit diagnostics associated with the surrounding function.
Kind = isOpenMPDeviceDelayedContext(*this)
? SemaDiagnosticBuilder::K_Deferred
: SemaDiagnosticBuilder::K_Immediate;
@ -1925,14 +1931,15 @@ Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
}
}
return SemaDiagnosticBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
return SemaDiagnosticBuilder(Kind, Loc, DiagID, FD, *this);
}
Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
unsigned DiagID) {
unsigned DiagID,
FunctionDecl *FD) {
assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
"Expected OpenMP host compilation.");
FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
FunctionEmissionStatus FES = getEmissionStatus(FD);
SemaDiagnosticBuilder::Kind Kind = SemaDiagnosticBuilder::K_Nop;
switch (FES) {
case FunctionEmissionStatus::Emitted:
@ -1948,7 +1955,7 @@ Sema::SemaDiagnosticBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
break;
}
return SemaDiagnosticBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
return SemaDiagnosticBuilder(Kind, Loc, DiagID, FD, *this);
}
static OpenMPDefaultmapClauseKind

View File

@ -12504,10 +12504,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCaptureDefault());
getDerived().transformedLocalDecl(OldClass, {Class});
Optional<std::tuple<unsigned, bool, Decl *>> Mangling;
Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling;
if (getDerived().ReplacingOriginal())
Mangling = std::make_tuple(OldClass->getLambdaManglingNumber(),
OldClass->hasKnownLambdaInternalLinkage(),
Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(),
OldClass->getLambdaManglingNumber(),
OldClass->getDeviceLambdaManglingNumber(),
OldClass->getLambdaContextDecl());
// Build the call operator.

View File

@ -1748,6 +1748,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.NumExplicitCaptures = Record.readInt();
Lambda.HasKnownInternalLinkage = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
D->setDeviceLambdaManglingNumber(Record.readInt());
Lambda.ContextDecl = readDeclID();
Lambda.Captures = (Capture *)Reader.getContext().Allocate(
sizeof(Capture) * Lambda.NumCaptures);

View File

@ -5667,6 +5667,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Lambda.NumExplicitCaptures);
Record->push_back(Lambda.HasKnownInternalLinkage);
Record->push_back(Lambda.ManglingNumber);
Record->push_back(D->getDeviceLambdaManglingNumber());
AddDeclRef(D->getLambdaContextDecl());
AddTypeSourceInfo(Lambda.MethodTyInfo);
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {

View File

@ -226,7 +226,7 @@
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_GETPWENT \
(SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
#define SANITIZER_INTERCEPT_GETPWENT_R \
(SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)

View File

@ -21,30 +21,30 @@
#include <locale.h>
#if defined(_LIBCPP_MSVCRT_LIKE)
# include <cstring>
# include <support/win32/locale_win32.h>
# include <__support/win32/locale_win32.h>
#elif defined(__NuttX__)
# include <support/nuttx/xlocale.h>
# include <__support/nuttx/xlocale.h>
#elif defined(_AIX) || defined(__MVS__)
# include <support/ibm/xlocale.h>
# include <__support/ibm/xlocale.h>
#elif defined(__ANDROID__)
# include <support/android/locale_bionic.h>
# include <__support/android/locale_bionic.h>
#elif defined(__sun__)
# include <xlocale.h>
# include <support/solaris/xlocale.h>
# include <__support/solaris/xlocale.h>
#elif defined(_NEWLIB_VERSION)
# include <support/newlib/xlocale.h>
# include <__support/newlib/xlocale.h>
#elif defined(__OpenBSD__)
# include <support/openbsd/xlocale.h>
# include <__support/openbsd/xlocale.h>
#elif (defined(__APPLE__) || defined(__FreeBSD__) \
|| defined(__EMSCRIPTEN__) || defined(__IBMCPP__))
# include <xlocale.h>
#elif defined(__Fuchsia__)
# include <support/fuchsia/xlocale.h>
# include <__support/fuchsia/xlocale.h>
#elif defined(__wasi__)
// WASI libc uses musl's locales support.
# include <support/musl/xlocale.h>
# include <__support/musl/xlocale.h>
#elif defined(_LIBCPP_HAS_MUSL_LIBC)
# include <support/musl/xlocale.h>
# include <__support/musl/xlocale.h>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)

View File

@ -17,7 +17,7 @@
#include <errno.h>
#ifdef __MVS__
# include <support/ibm/nanosleep.h>
# include <__support/ibm/nanosleep.h>
#endif
#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER

View File

@ -62,7 +62,7 @@ namespace std {
#include <__debug>
#if defined(__IBMCPP__)
#include "support/ibm/support.h"
#include "__support/ibm/support.h"
#endif
#if defined(_LIBCPP_COMPILER_MSVC)
#include <intrin.h>

View File

@ -105,11 +105,11 @@ template<> class numeric_limits<cv long double>;
#include <type_traits>
#if defined(_LIBCPP_COMPILER_MSVC)
#include "support/win32/limits_msvc_win32.h"
#include "__support/win32/limits_msvc_win32.h"
#endif // _LIBCPP_MSVCRT
#if defined(__IBMCPP__)
#include "support/ibm/limits.h"
#include "__support/ibm/limits.h"
#endif // __IBMCPP__
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)

View File

@ -2647,7 +2647,7 @@ private:
_Alloc *__alloc = reinterpret_cast<_Alloc*>(__first);
return __alloc;
}
_Tp* __get_elem() _NOEXCEPT {
_LIBCPP_NO_CFI _Tp* __get_elem() _NOEXCEPT {
_CompressedPair *__as_pair = reinterpret_cast<_CompressedPair*>(__blob_);
typename _CompressedPair::_Base2* __second = _CompressedPair::__get_second_base(__as_pair);
_Tp *__elem = reinterpret_cast<_Tp*>(__second);

View File

@ -19,6 +19,12 @@
#include <linux/futex.h>
#include <sys/syscall.h>
// libc++ uses SYS_futex as a universal syscall name. However, on 32 bit architectures
// with a 64 bit time_t, we need to specify SYS_futex_time64.
#if !defined(SYS_futex) && defined(SYS_futex_time64)
# define SYS_futex SYS_futex_time64
#endif
#else // <- Add other operating systems here
// Baseline needs no new headers

View File

@ -29,7 +29,7 @@
#include "cwctype"
#include "__sso_allocator"
#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
#include "support/win32/locale_win32.h"
#include "__support/win32/locale_win32.h"
#elif !defined(__BIONIC__) && !defined(__NuttX__)
#include <langinfo.h>
#endif

View File

@ -901,7 +901,10 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
continue;
}
if (expr != R_ABS && expr != R_DTPREL && expr != R_RISCV_ADD) {
// R_ABS/R_DTPREL and some other relocations can be used from non-SHF_ALLOC
// sections.
if (expr != R_ABS && expr != R_DTPREL && expr != R_GOTPLTREL &&
expr != R_RISCV_ADD) {
std::string msg = getLocation<ELFT>(offset) +
": has non-ABS relocation " + toString(type) +
" against symbol '" + toString(sym) + "'";

View File

@ -24,28 +24,124 @@ Non-comprehensive list of changes in this release
ELF Improvements
----------------
* ``--error-handling-script`` is added to allow for user-defined handlers upon
* ``--dependency-file`` has been added. (Similar to ``cc -M -MF``.)
(`D82437 <https://reviews.llvm.org/D82437>`_)
* ``--error-handling-script`` has been added to allow for user-defined handlers upon
missing libraries. (`D87758 <https://reviews.llvm.org/D87758>`_)
* ``--exclude-libs`` can now localize defined version symbols and bitcode referenced libcall symbols.
(`D94280 <https://reviews.llvm.org/D94280>`_)
* ``--gdb-index`` now works with DWARF v5 and ``--icf={safe,all}``.
(`D85579 <https://reviews.llvm.org/D85579>`_)
(`D89751 <https://reviews.llvm.org/D89751>`_)
* ``--gdb-index --emit-relocs`` can now be used together.
(`D94354 <https://reviews.llvm.org/D94354>`_)
* ``--icf={safe,all}`` conservatively no longer fold text sections with LSDA.
Previously ICF on ``-fexceptions`` code could be unsafe.
(`D84610 <https://reviews.llvm.org/D84610>`_)
* ``--icf={safe,all}`` can now fold two sections with relocations referencing aliased symbols.
(`D88830 <https://reviews.llvm.org/D88830>`_)
* ``--lto-pseudo-probe-for-profiling`` has been added.
(`D95056 <https://reviews.llvm.org/D95056>`_)
* ``--no-lto-whole-program-visibility`` has been added.
(`D92060 <https://reviews.llvm.org/D92060>`_)
* ``--oformat-binary`` has been fixed to respect LMA.
(`D85086 <https://reviews.llvm.org/D85086>`_)
* ``--reproduce`` includes ``--lto-sample-profile``, ``--just-symbols``, ``--call-graph-ordering-file``, ``--retain-symbols-file`` files.
* ``-r --gc-sections`` is now supported.
(`D84131 <https://reviews.llvm.org/D84131>`_)
* A ``-u`` specified symbol will no longer change the binding to ``STB_WEAK``.
(`D88945 <https://reviews.llvm.org/D88945>`_)
* ``--wrap`` support has been improved.
+ If ``foo`` is not referenced, there is no longer an undefined symbol ``__wrap_foo``.
+ If ``__real_foo`` is not referenced, there is no longer an undefined symbol ``foo``.
* ``SHF_LINK_ORDER`` sections can now have zero ``sh_link`` values.
* ``SHF_LINK_ORDER`` and non-``SHF_LINK_ORDER`` sections can now be mixed within an input section description.
(`D84001 <https://reviews.llvm.org/D84001>`_)
* ``LOG2CEIL`` is now supported in linker scripts.
(`D84054 <https://reviews.llvm.org/D84054>`_)
* ``DEFINED`` has been fixed to check whether the symbol is defined.
(`D83758 <https://reviews.llvm.org/D83758>`_)
* An input section description may now have multiple ``SORT_*``.
The matched sections are ordered by radix sort with the keys being ``(SORT*, --sort-section, input order)``.
(`D91127 <https://reviews.llvm.org/D91127>`_)
* Users can now provide a GNU style linker script to convert ``.ctors`` into ``.init_array``.
(`D91187 <https://reviews.llvm.org/D91187>`_)
* An empty output section can now be discarded even if it is assigned to a program header.
(`D92301 <https://reviews.llvm.org/D92301>`_)
* Non-``SHF_ALLOC`` sections now have larger file offsets than ``SHF_ALLOC`` sections.
(`D85867 <https://reviews.llvm.org/D85867>`_)
* Some symbol versioning improvements.
+ Defined ``foo@@v1`` now resolve undefined ``foo@v1`` (`D92259 <https://reviews.llvm.org/D92259>`_)
+ Undefined ``foo@v1`` now gets an error (`D92260 <https://reviews.llvm.org/D92260>`_)
* The AArch64 port now has support for ``STO_AARCH64_VARIANT_PCS`` and ``DT_AARCH64_VARIANT_PCS``.
(`D93045 <https://reviews.llvm.org/D93045>`_)
* The AArch64 port now has support for ``R_AARCH64_LD64_GOTPAGE_LO15``.
* The PowerPC64 port now detects missing R_PPC64_TLSGD/R_PPC64_TLSLD and disables TLS relaxation.
This allows linking with object files produced by very old IBM XL compilers.
(`D92959 <https://reviews.llvm.org/D92959>`_)
* Many PowerPC PC-relative relocations are now supported.
* ``R_PPC_ADDR24`` and ``R_PPC64_ADDR16_HIGH`` are now supported.
* powerpcle is now supported. Tested with FreeBSD loader and freestanding.
(`D93917 <https://reviews.llvm.org/D93917>`_)
* RISC-V: the first ``SHT_RISCV_ATTRIBUTES`` section is now retained.
(`D86309 <https://reviews.llvm.org/D86309>`_)
* LTO pipeline now defaults to the new PM if the CMake variable ``ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER`` is on.
(`D92885 <https://reviews.llvm.org/D92885>`_)
Breaking changes
----------------
* ...
* A COMMON symbol can now cause the fetch of an archive providing a ``STB_GLOBAL`` definition.
This behavior follows GNU ld newer than December 1999.
If you see ``duplicate symbol`` errors with the new behavior, check out `PR49226 <https://bugs.llvm.org//show_bug.cgi?id=49226>`_.
(`D86142 <https://reviews.llvm.org/D86142>`_)
COFF Improvements
-----------------
* ...
* Error out clearly if creating a DLL with too many exported symbols.
(`D86701 <https://reviews.llvm.org/D86701>`_)
MinGW Improvements
------------------
* ...
* Enabled dynamicbase by default. (`D86654 <https://reviews.llvm.org/D86654>`_)
MachO Improvements
* Tolerate mismatches between COMDAT section sizes with different amount of
padding (produced by binutils) by inspecting the aux section definition.
(`D86659 <https://reviews.llvm.org/D86659>`_)
* Support setting the subsystem version via the subsystem argument.
(`D88804 <https://reviews.llvm.org/D88804>`_)
* Implemented the GNU -wrap option.
(`D89004 <https://reviews.llvm.org/D89004>`_,
`D91689 <https://reviews.llvm.org/D91689>`_)
* Handle the ``--demangle`` and ``--no-demangle`` options.
(`D93950 <https://reviews.llvm.org/D93950>`_)
Mach-O Improvements
------------------
* Item 1.
We've gotten the new implementation of LLD for Mach-O to the point where it is
able to link large x86_64 programs, and we'd love to get some alpha testing on
it. The new Darwin back-end can be invoked as follows:
.. code-block::
clang -fuse-ld=lld.darwinnew /path/to/file.c
To reach this point, we implemented numerous features, and it's easier to list
the major features we *haven't* yet completed:
* LTO support
* Stack unwinding for exceptions
* Support for arm64, arm, and i386 architectures
If you stumble upon an issue and it doesn't fall into one of these categories,
please file a bug report!
WebAssembly Improvements
------------------------

View File

@ -522,7 +522,8 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d};
static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00};
static const uint8_t g_s390x_opcode[] = {0x00, 0x01};
static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; // trap
static const uint8_t g_ppcle_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap
switch (GetArchitecture().GetMachine()) {
case llvm::Triple::aarch64:
@ -544,8 +545,12 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
case llvm::Triple::systemz:
return llvm::makeArrayRef(g_s390x_opcode);
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
return llvm::makeArrayRef(g_ppc_opcode);
case llvm::Triple::ppc64le:
return llvm::makeArrayRef(g_ppc64le_opcode);
return llvm::makeArrayRef(g_ppcle_opcode);
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
@ -568,6 +573,8 @@ size_t NativeProcessProtocol::GetSoftwareBreakpointPCOffset() {
case llvm::Triple::mips64el:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
// On these architectures the PC doesn't get updated for breakpoint hits.
return 0;

View File

@ -214,55 +214,9 @@ void PlatformFreeBSD::GetStatus(Stream &strm) {
#endif
}
size_t
PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target,
BreakpointSite *bp_site) {
switch (target.GetArchitecture().GetMachine()) {
case llvm::Triple::arm: {
lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0));
AddressClass addr_class = AddressClass::eUnknown;
if (bp_loc_sp) {
addr_class = bp_loc_sp->GetAddress().GetAddressClass();
if (addr_class == AddressClass::eUnknown &&
(bp_loc_sp->GetAddress().GetFileAddress() & 1))
addr_class = AddressClass::eCodeAlternateISA;
}
if (addr_class == AddressClass::eCodeAlternateISA) {
// TODO: Enable when FreeBSD supports thumb breakpoints.
// FreeBSD kernel as of 10.x, does not support thumb breakpoints
return 0;
}
static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7};
size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
assert(bp_site);
if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size))
return trap_opcode_size;
}
LLVM_FALLTHROUGH;
default:
return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
}
}
bool PlatformFreeBSD::CanDebugProcess() {
if (IsHost()) {
llvm::Triple host_triple{llvm::sys::getProcessTriple()};
bool use_legacy_plugin;
switch (host_triple.getArch()) {
case llvm::Triple::x86:
case llvm::Triple::x86_64:
// FreeBSDRemote plugin supports x86 only at the moment
use_legacy_plugin = !!getenv("FREEBSD_LEGACY_PLUGIN");
break;
default:
use_legacy_plugin = true;
}
return !use_legacy_plugin;
return true;
} else {
// If we're connected, we can debug.
return IsConnected();

View File

@ -44,9 +44,6 @@ class PlatformFreeBSD : public PlatformPOSIX {
bool CanDebugProcess() override;
size_t GetSoftwareBreakpointTrapOpcode(Target &target,
BreakpointSite *bp_site) override;
void CalculateTrapHandlerSymbolNames() override;
MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,

View File

@ -1,615 +0,0 @@
//===-- FreeBSDThread.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
//
//===----------------------------------------------------------------------===//
#include <errno.h>
#include <pthread.h>
#include <pthread_np.h>
#include <stdlib.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
#include "FreeBSDThread.h"
#include "POSIXStopInfo.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
#include "RegisterContextPOSIXProcessMonitor_x86.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostNativeThread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Target/Unwind.h"
#include "lldb/Utility/State.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid)
: Thread(process, tid), m_frame_up(), m_breakpoint(),
m_thread_name_valid(false), m_thread_name(), m_posix_thread(nullptr) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOGV(log, "tid = {0}", tid);
// Set the current watchpoints for this thread.
Target &target = GetProcess()->GetTarget();
const WatchpointList &wp_list = target.GetWatchpointList();
size_t wp_size = wp_list.GetSize();
for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++) {
lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
if (wp.get() && wp->IsEnabled()) {
// This watchpoint as been enabled; obviously this "new" thread has been
// created since that watchpoint was enabled. Since the
// POSIXBreakpointProtocol has yet to be initialized, its
// m_watchpoints_initialized member will be FALSE. Attempting to read
// the debug status register to determine if a watchpoint has been hit
// would result in the zeroing of that register. Since the active debug
// registers would have been cloned when this thread was created, simply
// force the m_watchpoints_initized member to TRUE and avoid resetting
// dr6 and dr7.
GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized();
}
}
}
FreeBSDThread::~FreeBSDThread() { DestroyThread(); }
ProcessMonitor &FreeBSDThread::GetMonitor() {
ProcessSP base = GetProcess();
ProcessFreeBSD &process = static_cast<ProcessFreeBSD &>(*base);
return process.GetMonitor();
}
void FreeBSDThread::RefreshStateAfterStop() {
// Invalidate all registers in our register context. We don't set "force" to
// true because the stop reply packet might have had some register values
// that were expedited and these will already be copied into the register
// context by the time this function gets called. The KDPRegisterContext
// class has been made smart enough to detect when it needs to invalidate
// which registers are valid by putting hooks in the register read and
// register supply functions where they check the process stop ID and do the
// right thing. if (StateIsStoppedState(GetState())
{
const bool force = false;
GetRegisterContext()->InvalidateIfNeeded(force);
}
}
const char *FreeBSDThread::GetInfo() { return nullptr; }
void FreeBSDThread::SetName(const char *name) {
m_thread_name_valid = (name && name[0]);
if (m_thread_name_valid)
m_thread_name.assign(name);
else
m_thread_name.clear();
}
const char *FreeBSDThread::GetName() {
if (!m_thread_name_valid) {
m_thread_name.clear();
int pid = GetProcess()->GetID();
struct kinfo_proc *kp = nullptr, *nkp;
size_t len = 0;
int error;
int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
pid};
while (1) {
error = sysctl(ctl, 4, kp, &len, nullptr, 0);
if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
// Add extra space in case threads are added before next call.
len += sizeof(*kp) + len / 10;
nkp = (struct kinfo_proc *)realloc(kp, len);
if (nkp == nullptr) {
free(kp);
return nullptr;
}
kp = nkp;
continue;
}
if (error != 0)
len = 0;
break;
}
for (size_t i = 0; i < len / sizeof(*kp); i++) {
if (kp[i].ki_tid == (lwpid_t)GetID()) {
m_thread_name.append(kp[i].ki_tdname,
kp[i].ki_tdname + strlen(kp[i].ki_tdname));
break;
}
}
free(kp);
m_thread_name_valid = true;
}
if (m_thread_name.empty())
return nullptr;
return m_thread_name.c_str();
}
lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() {
if (!m_reg_context_sp) {
m_posix_thread = nullptr;
RegisterInfoInterface *reg_interface = nullptr;
const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture();
switch (target_arch.GetMachine()) {
case llvm::Triple::aarch64:
case llvm::Triple::arm:
break;
case llvm::Triple::ppc:
#ifndef __powerpc64__
reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch);
break;
#endif
case llvm::Triple::ppc64:
reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch);
break;
case llvm::Triple::mips64:
reg_interface = new RegisterContextFreeBSD_mips64(target_arch);
break;
case llvm::Triple::x86:
reg_interface = new RegisterContextFreeBSD_i386(target_arch);
break;
case llvm::Triple::x86_64:
reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
break;
default:
llvm_unreachable("CPU not supported");
}
switch (target_arch.GetMachine()) {
case llvm::Triple::aarch64: {
RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx =
new RegisterContextPOSIXProcessMonitor_arm64(
*this, std::make_unique<RegisterInfoPOSIX_arm64>(target_arch));
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
case llvm::Triple::arm: {
RegisterContextPOSIXProcessMonitor_arm *reg_ctx =
new RegisterContextPOSIXProcessMonitor_arm(
*this, std::make_unique<RegisterInfoPOSIX_arm>(target_arch));
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
case llvm::Triple::mips64: {
RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx =
new RegisterContextPOSIXProcessMonitor_mips64(*this, 0,
reg_interface);
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
case llvm::Triple::ppc:
case llvm::Triple::ppc64: {
RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx =
new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0,
reg_interface);
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
case llvm::Triple::x86:
case llvm::Triple::x86_64: {
RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx =
new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0,
reg_interface);
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
}
default:
break;
}
}
return m_reg_context_sp;
}
lldb::RegisterContextSP
FreeBSDThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
lldb::RegisterContextSP reg_ctx_sp;
uint32_t concrete_frame_idx = 0;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOGV(log, "called");
if (frame)
concrete_frame_idx = frame->GetConcreteFrameIndex();
if (concrete_frame_idx == 0)
reg_ctx_sp = GetRegisterContext();
else {
reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
}
return reg_ctx_sp;
}
lldb::addr_t FreeBSDThread::GetThreadPointer() {
ProcessMonitor &monitor = GetMonitor();
addr_t addr;
if (monitor.ReadThreadPointer(GetID(), addr))
return addr;
else
return LLDB_INVALID_ADDRESS;
}
bool FreeBSDThread::CalculateStopInfo() {
SetStopInfo(m_stop_info_sp);
return true;
}
void FreeBSDThread::DidStop() {
// Don't set the thread state to stopped unless we really stopped.
}
void FreeBSDThread::WillResume(lldb::StateType resume_state) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOGF(log, "tid %" PRIu64 " resume_state = %s", GetID(),
lldb_private::StateAsCString(resume_state));
ProcessSP process_sp(GetProcess());
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get());
int signo = GetResumeSignal();
bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo);
switch (resume_state) {
case eStateSuspended:
case eStateStopped:
process->m_suspend_tids.push_back(GetID());
break;
case eStateRunning:
process->m_run_tids.push_back(GetID());
if (signo_valid)
process->m_resume_signo = signo;
break;
case eStateStepping:
process->m_step_tids.push_back(GetID());
if (signo_valid)
process->m_resume_signo = signo;
break;
default:
break;
}
}
bool FreeBSDThread::Resume() {
lldb::StateType resume_state = GetResumeState();
ProcessMonitor &monitor = GetMonitor();
bool status;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOGF(log, "FreeBSDThread::%s (), resume_state = %s", __FUNCTION__,
StateAsCString(resume_state));
switch (resume_state) {
default:
assert(false && "Unexpected state for resume!");
status = false;
break;
case lldb::eStateRunning:
SetState(resume_state);
status = monitor.Resume(GetID(), GetResumeSignal());
break;
case lldb::eStateStepping:
SetState(resume_state);
status = monitor.SingleStep(GetID(), GetResumeSignal());
break;
case lldb::eStateStopped:
case lldb::eStateSuspended:
status = true;
break;
}
return status;
}
void FreeBSDThread::Notify(const ProcessMessage &message) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
LLDB_LOGF(log, "FreeBSDThread::%s () message kind = '%s' for tid %" PRIu64,
__FUNCTION__, message.PrintKind(), GetID());
switch (message.GetKind()) {
default:
assert(false && "Unexpected message kind!");
break;
case ProcessMessage::eExitMessage:
// Nothing to be done.
break;
case ProcessMessage::eLimboMessage:
LimboNotify(message);
break;
case ProcessMessage::eCrashMessage:
case ProcessMessage::eSignalMessage:
SignalNotify(message);
break;
case ProcessMessage::eSignalDeliveredMessage:
SignalDeliveredNotify(message);
break;
case ProcessMessage::eTraceMessage:
TraceNotify(message);
break;
case ProcessMessage::eBreakpointMessage:
BreakNotify(message);
break;
case ProcessMessage::eWatchpointMessage:
WatchNotify(message);
break;
case ProcessMessage::eExecMessage:
ExecNotify(message);
break;
}
}
bool FreeBSDThread::EnableHardwareWatchpoint(Watchpoint *wp) {
bool wp_set = false;
if (wp) {
addr_t wp_addr = wp->GetLoadAddress();
size_t wp_size = wp->GetByteSize();
bool wp_read = wp->WatchpointRead();
bool wp_write = wp->WatchpointWrite();
uint32_t wp_hw_index = wp->GetHardwareIndex();
POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol();
if (reg_ctx)
wp_set = reg_ctx->SetHardwareWatchpointWithIndex(
wp_addr, wp_size, wp_read, wp_write, wp_hw_index);
}
return wp_set;
}
bool FreeBSDThread::DisableHardwareWatchpoint(Watchpoint *wp) {
bool result = false;
if (wp) {
lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
if (reg_ctx_sp.get())
result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
}
return result;
}
uint32_t FreeBSDThread::NumSupportedHardwareWatchpoints() {
lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
if (reg_ctx_sp.get())
return reg_ctx_sp->NumSupportedHardwareWatchpoints();
return 0;
}
uint32_t FreeBSDThread::FindVacantWatchpointIndex() {
uint32_t hw_index = LLDB_INVALID_INDEX32;
uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
uint32_t wp_idx;
POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol();
if (reg_ctx) {
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) {
if (reg_ctx->IsWatchpointVacant(wp_idx)) {
hw_index = wp_idx;
break;
}
}
}
return hw_index;
}
void FreeBSDThread::BreakNotify(const ProcessMessage &message) {
bool status;
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
assert(GetRegisterContext());
status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint();
assert(status && "Breakpoint update failed!");
// With our register state restored, resolve the breakpoint object
// corresponding to our current PC.
assert(GetRegisterContext());
lldb::addr_t pc = GetRegisterContext()->GetPC();
LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
lldb::BreakpointSiteSP bp_site(
GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
// If the breakpoint is for this thread, then we'll report the hit, but if it
// is for another thread, we create a stop reason with should_stop=false. If
// there is no breakpoint location, then report an invalid stop reason. We
// don't need to worry about stepping over the breakpoint here, that will be
// taken care of when the thread resumes and notices that there's a
// breakpoint under the pc.
if (bp_site) {
lldb::break_id_t bp_id = bp_site->GetID();
// If we have an operating system plug-in, we might have set a thread
// specific breakpoint using the operating system thread ID, so we can't
// make any assumptions about the thread ID so we must always report the
// breakpoint regardless of the thread.
if (bp_site->ValidForThisThread(this) ||
GetProcess()->GetOperatingSystem() != nullptr)
SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
else {
const bool should_stop = false;
SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id,
should_stop));
}
} else
SetStopInfo(StopInfoSP());
}
void FreeBSDThread::WatchNotify(const ProcessMessage &message) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
lldb::addr_t halt_addr = message.GetHWAddress();
LLDB_LOGF(log,
"FreeBSDThread::%s () Hardware Watchpoint Address = 0x%8.8" PRIx64,
__FUNCTION__, halt_addr);
POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol();
if (reg_ctx) {
uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
uint32_t wp_idx;
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) {
if (reg_ctx->IsWatchpointHit(wp_idx)) {
// Clear the watchpoint hit here
reg_ctx->ClearWatchpointHits();
break;
}
}
if (wp_idx == num_hw_wps)
return;
Target &target = GetProcess()->GetTarget();
lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
const WatchpointList &wp_list = target.GetWatchpointList();
lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
assert(wp_sp.get() && "No watchpoint found");
SetStopInfo(
StopInfo::CreateStopReasonWithWatchpointID(*this, wp_sp->GetID()));
}
}
void FreeBSDThread::TraceNotify(const ProcessMessage &message) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
// Try to resolve the breakpoint object corresponding to the current PC.
assert(GetRegisterContext());
lldb::addr_t pc = GetRegisterContext()->GetPC();
LLDB_LOGF(log, "FreeBSDThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
lldb::BreakpointSiteSP bp_site(
GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
// If the current pc is a breakpoint site then set the StopInfo to
// Breakpoint. Otherwise, set the StopInfo to Watchpoint or Trace. If we have
// an operating system plug-in, we might have set a thread specific
// breakpoint using the operating system thread ID, so we can't make any
// assumptions about the thread ID so we must always report the breakpoint
// regardless of the thread.
if (bp_site && (bp_site->ValidForThisThread(this) ||
GetProcess()->GetOperatingSystem() != nullptr))
SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID(
*this, bp_site->GetID()));
else {
POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol();
if (reg_ctx) {
uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
uint32_t wp_idx;
for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) {
if (reg_ctx->IsWatchpointHit(wp_idx)) {
WatchNotify(message);
return;
}
}
}
SetStopInfo(StopInfo::CreateStopReasonToTrace(*this));
}
}
void FreeBSDThread::LimboNotify(const ProcessMessage &message) {
SetStopInfo(lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
}
void FreeBSDThread::SignalNotify(const ProcessMessage &message) {
int signo = message.GetSignal();
if (message.GetKind() == ProcessMessage::eCrashMessage) {
std::string stop_description = GetCrashReasonString(
message.GetCrashReason(), message.GetFaultAddress());
SetStopInfo(StopInfo::CreateStopReasonWithSignal(
*this, signo, stop_description.c_str()));
} else {
SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo));
}
}
void FreeBSDThread::SignalDeliveredNotify(const ProcessMessage &message) {
int signo = message.GetSignal();
SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, signo));
}
unsigned FreeBSDThread::GetRegisterIndexFromOffset(unsigned offset) {
unsigned reg = LLDB_INVALID_REGNUM;
ArchSpec arch = HostInfo::GetArchitecture();
switch (arch.GetMachine()) {
default:
llvm_unreachable("CPU type not supported!");
break;
case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::mips64:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::x86:
case llvm::Triple::x86_64: {
POSIXBreakpointProtocol *reg_ctx = GetPOSIXBreakpointProtocol();
reg = reg_ctx->GetRegisterIndexFromOffset(offset);
} break;
}
return reg;
}
void FreeBSDThread::ExecNotify(const ProcessMessage &message) {
SetStopInfo(StopInfo::CreateStopReasonWithExec(*this));
}
const char *FreeBSDThread::GetRegisterName(unsigned reg) {
const char *name = nullptr;
ArchSpec arch = HostInfo::GetArchitecture();
switch (arch.GetMachine()) {
default:
assert(false && "CPU type not supported!");
break;
case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::mips64:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
name = GetRegisterContext()->GetRegisterName(reg);
break;
}
return name;
}
const char *FreeBSDThread::GetRegisterNameFromOffset(unsigned offset) {
return GetRegisterName(GetRegisterIndexFromOffset(offset));
}

View File

@ -1,111 +0,0 @@
//===-- FreeBSDThread.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_FreeBSDThread_H_
#define liblldb_FreeBSDThread_H_
#include <memory>
#include <string>
#include "RegisterContextPOSIX.h"
#include "lldb/Target/Thread.h"
class ProcessMessage;
class ProcessMonitor;
class POSIXBreakpointProtocol;
// @class FreeBSDThread
// Abstraction of a FreeBSD thread.
class FreeBSDThread : public lldb_private::Thread {
public:
// Constructors and destructors
FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid);
virtual ~FreeBSDThread();
// POSIXThread
void RefreshStateAfterStop() override;
// This notifies the thread when a private stop occurs.
void DidStop() override;
const char *GetInfo() override;
void SetName(const char *name) override;
const char *GetName() override;
lldb::RegisterContextSP GetRegisterContext() override;
lldb::RegisterContextSP
CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
lldb::addr_t GetThreadPointer() override;
// These functions provide a mapping from the register offset
// back to the register index or name for use in debugging or log
// output.
unsigned GetRegisterIndexFromOffset(unsigned offset);
const char *GetRegisterName(unsigned reg);
const char *GetRegisterNameFromOffset(unsigned offset);
// These methods form a specialized interface to POSIX threads.
//
bool Resume();
void Notify(const ProcessMessage &message);
// These methods provide an interface to watchpoints
//
bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
uint32_t NumSupportedHardwareWatchpoints();
uint32_t FindVacantWatchpointIndex();
protected:
POSIXBreakpointProtocol *GetPOSIXBreakpointProtocol() {
if (!m_reg_context_sp)
m_reg_context_sp = GetRegisterContext();
return m_posix_thread;
}
std::unique_ptr<lldb_private::StackFrame> m_frame_up;
lldb::BreakpointSiteSP m_breakpoint;
bool m_thread_name_valid;
std::string m_thread_name;
POSIXBreakpointProtocol *m_posix_thread;
ProcessMonitor &GetMonitor();
bool CalculateStopInfo() override;
void BreakNotify(const ProcessMessage &message);
void WatchNotify(const ProcessMessage &message);
virtual void TraceNotify(const ProcessMessage &message);
void LimboNotify(const ProcessMessage &message);
void SignalNotify(const ProcessMessage &message);
void SignalDeliveredNotify(const ProcessMessage &message);
void CrashNotify(const ProcessMessage &message);
void ExitNotify(const ProcessMessage &message);
void ExecNotify(const ProcessMessage &message);
// FreeBSDThread internal API.
// POSIXThread override
virtual void WillResume(lldb::StateType resume_state) override;
};
#endif // #ifndef liblldb_FreeBSDThread_H_

View File

@ -213,8 +213,9 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
llvm::Error error = t.CopyWatchpointsFrom(
static_cast<NativeThreadFreeBSD &>(*GetCurrentThread()));
if (error) {
LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
info.pl_lwpid, llvm::toString(std::move(error)));
LLDB_LOG_ERROR(log, std::move(error),
"failed to copy watchpoints to new thread {1}: {0}",
info.pl_lwpid);
SetState(StateType::eStateInvalid);
return;
}
@ -264,19 +265,35 @@ void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
switch (info.pl_siginfo.si_code) {
case TRAP_BRKPT:
LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}",
info.pl_siginfo.si_addr);
if (thread) {
thread->SetStoppedByBreakpoint();
auto thread_info =
m_threads_stepping_with_breakpoint.find(thread->GetID());
if (thread_info != m_threads_stepping_with_breakpoint.end()) {
thread->SetStoppedByTrace();
Status brkpt_error = RemoveBreakpoint(thread_info->second);
if (brkpt_error.Fail())
LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}",
thread_info->first, brkpt_error);
m_threads_stepping_with_breakpoint.erase(thread_info);
} else
thread->SetStoppedByBreakpoint();
FixupBreakpointPCAsNeeded(*thread);
}
SetState(StateType::eStateStopped, true);
return;
case TRAP_TRACE:
LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}",
info.pl_siginfo.si_addr);
if (thread) {
auto &regctx = static_cast<NativeRegisterContextFreeBSD &>(
thread->GetRegisterContext());
uint32_t wp_index = LLDB_INVALID_INDEX32;
Status error =
regctx.GetWatchpointHitIndex(wp_index, LLDB_INVALID_ADDRESS);
Status error = regctx.GetWatchpointHitIndex(
wp_index, reinterpret_cast<uintptr_t>(info.pl_siginfo.si_addr));
if (error.Fail())
LLDB_LOG(log,
"received error while checking for watchpoint hits, pid = "
@ -354,6 +371,27 @@ Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
return error;
}
llvm::Expected<llvm::ArrayRef<uint8_t>>
NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7};
static const uint8_t g_thumb_opcode[] = {0x01, 0xde};
switch (GetArchitecture().GetMachine()) {
case llvm::Triple::arm:
switch (size_hint) {
case 2:
return llvm::makeArrayRef(g_thumb_opcode);
case 4:
return llvm::makeArrayRef(g_arm_opcode);
default:
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"Unrecognised trap opcode size hint!");
}
default:
return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
}
}
Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
LLDB_LOG(log, "pid {0}", GetID());
@ -623,9 +661,8 @@ size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); }
Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
bool hardware) {
if (hardware)
return Status("NativeProcessFreeBSD does not support hardware breakpoints");
else
return SetSoftwareBreakpoint(addr, size);
return SetHardwareBreakpoint(addr, size);
return SetSoftwareBreakpoint(addr, size);
}
Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path,
@ -878,3 +915,7 @@ Status NativeProcessFreeBSD::ReinitializeThreads() {
return error;
}
bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const {
return !m_arch.IsMIPS();
}

View File

@ -10,6 +10,8 @@
#define liblldb_NativeProcessFreeBSD_H_
#include "Plugins/Process/POSIX/NativeProcessELF.h"
#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/FileSpec.h"
@ -25,7 +27,8 @@ namespace process_freebsd {
/// for debugging.
///
/// Changes in the inferior process state are broadcasted.
class NativeProcessFreeBSD : public NativeProcessELF {
class NativeProcessFreeBSD : public NativeProcessELF,
private NativeProcessSoftwareSingleStep {
public:
class Factory : public NativeProcessProtocol::Factory {
public:
@ -84,6 +87,12 @@ class NativeProcessFreeBSD : public NativeProcessELF {
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
int data = 0, int *result = nullptr);
bool SupportHardwareSingleStepping() const;
protected:
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
private:
MainLoop::SignalHandleUP m_sigchld_handle;
ArchSpec m_arch;

View File

@ -8,7 +8,7 @@
#include "NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
#include "lldb/Host/common/NativeProcessProtocol.h"

View File

@ -0,0 +1,202 @@
//===-- NativeRegisterContextFreeBSD_arm.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
//
//===----------------------------------------------------------------------===//
#if defined(__arm__)
#include "NativeRegisterContextFreeBSD_arm.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
// clang-format off
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
// clang-format on
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_freebsd;
NativeRegisterContextFreeBSD *
NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread);
}
NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
: NativeRegisterContextRegisterInfo(
native_thread, new RegisterInfoPOSIX_arm(target_arch)) {}
RegisterInfoPOSIX_arm &
NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const {
return static_cast<RegisterInfoPOSIX_arm &>(*m_register_info_interface_up);
}
uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const {
return GetRegisterInfo().GetRegisterSetCount();
}
const RegisterSet *
NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const {
return GetRegisterInfo().GetRegisterSet(set_index);
}
uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const {
uint32_t count = 0;
for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
count += GetRegisterSet(set_index)->num_registers;
return count;
}
Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) {
switch (set) {
case RegisterInfoPOSIX_arm::GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
m_reg_data.data());
case RegisterInfoPOSIX_arm::FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(
PT_GETVFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
}
llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet");
}
Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) {
switch (set) {
case RegisterInfoPOSIX_arm::GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
m_reg_data.data());
case RegisterInfoPOSIX_arm::FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(
PT_SETVFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR));
}
llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet");
}
Status
NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) {
Status error;
if (!reg_info) {
error.SetErrorString("reg_info NULL");
return error;
}
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
reg_info->byte_size, endian::InlHostByteOrder());
return error;
}
Status NativeRegisterContextFreeBSD_arm::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &reg_value) {
Status error;
if (!reg_info)
return Status("reg_info NULL");
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
reg_info->byte_size);
return WriteRegisterSet(set);
}
Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues(
lldb::DataBufferSP &data_sp) {
Status error;
error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
if (error.Fail())
return error;
error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
if (error.Fail())
return error;
data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
uint8_t *dst = data_sp->GetBytes();
::memcpy(dst, m_reg_data.data(), m_reg_data.size());
return error;
}
Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues(
const lldb::DataBufferSP &data_sp) {
Status error;
if (!data_sp) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided",
__FUNCTION__);
return error;
}
if (data_sp->GetByteSize() != m_reg_data.size()) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched "
"data size, expected %" PRIu64 ", actual %" PRIu64,
__FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
return error;
}
uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s "
"DataBuffer::GetBytes() returned a null "
"pointer",
__FUNCTION__);
return error;
}
::memcpy(m_reg_data.data(), src, m_reg_data.size());
error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet);
if (error.Fail())
return error;
return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet);
}
llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom(
NativeRegisterContextFreeBSD &source) {
return llvm::Error::success();
}
#endif // defined (__arm__)

View File

@ -0,0 +1,68 @@
//===-- NativeRegisterContextFreeBSD_arm.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
//
//===----------------------------------------------------------------------===//
#if defined(__arm__)
#ifndef lldb_NativeRegisterContextFreeBSD_arm_h
#define lldb_NativeRegisterContextFreeBSD_arm_h
// clang-format off
#include <sys/types.h>
#include <machine/reg.h>
#include <machine/vfp.h>
// clang-format on
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
#include <array>
namespace lldb_private {
namespace process_freebsd {
class NativeProcessFreeBSD;
class NativeRegisterContextFreeBSD_arm : public NativeRegisterContextFreeBSD {
public:
NativeRegisterContextFreeBSD_arm(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
private:
std::array<uint8_t, sizeof(reg) + sizeof(vfp_state)> m_reg_data;
Status ReadRegisterSet(uint32_t set);
Status WriteRegisterSet(uint32_t set);
RegisterInfoPOSIX_arm &GetRegisterInfo() const;
};
} // namespace process_freebsd
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm_h
#endif // defined (__arm__)

View File

@ -0,0 +1,288 @@
//===-- NativeRegisterContextFreeBSD_arm64.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
//
//===----------------------------------------------------------------------===//
#if defined(__aarch64__)
#include "NativeRegisterContextFreeBSD_arm64.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
// clang-format off
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
// clang-format on
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_freebsd;
NativeRegisterContextFreeBSD *
NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread);
}
NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
: NativeRegisterContextRegisterInfo(
native_thread, new RegisterInfoPOSIX_arm64(target_arch))
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
,
m_read_dbreg(false)
#endif
{
GetRegisterInfo().ConfigureVectorRegisterInfos(
RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64);
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
}
RegisterInfoPOSIX_arm64 &
NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const {
return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up);
}
uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const {
return GetRegisterInfo().GetRegisterSetCount();
}
const RegisterSet *
NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const {
return GetRegisterInfo().GetRegisterSet(set_index);
}
uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const {
uint32_t count = 0;
for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
count += GetRegisterSet(set_index)->num_registers;
return count;
}
Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) {
switch (set) {
case RegisterInfoPOSIX_arm64::GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
m_reg_data.data());
case RegisterInfoPOSIX_arm64::FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(
PT_GETFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
case RegisterInfoPOSIX_arm64::SVERegSet:
return Status("not supported");
}
llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet");
}
Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) {
switch (set) {
case RegisterInfoPOSIX_arm64::GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
m_reg_data.data());
case RegisterInfoPOSIX_arm64::FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(
PT_SETFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR));
case RegisterInfoPOSIX_arm64::SVERegSet:
return Status("not supported");
}
llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet");
}
Status
NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) {
Status error;
if (!reg_info) {
error.SetErrorString("reg_info NULL");
return error;
}
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
reg_info->byte_size, endian::InlHostByteOrder());
return error;
}
Status NativeRegisterContextFreeBSD_arm64::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &reg_value) {
Status error;
if (!reg_info)
return Status("reg_info NULL");
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg);
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
reg_info->byte_size);
return WriteRegisterSet(set);
}
Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues(
lldb::DataBufferSP &data_sp) {
Status error;
error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
if (error.Fail())
return error;
error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
if (error.Fail())
return error;
data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
uint8_t *dst = data_sp->GetBytes();
::memcpy(dst, m_reg_data.data(), m_reg_data.size());
return error;
}
Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues(
const lldb::DataBufferSP &data_sp) {
Status error;
if (!data_sp) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided",
__FUNCTION__);
return error;
}
if (data_sp->GetByteSize() != m_reg_data.size()) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched "
"data size, expected %" PRIu64 ", actual %" PRIu64,
__FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
return error;
}
uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s "
"DataBuffer::GetBytes() returned a null "
"pointer",
__FUNCTION__);
return error;
}
::memcpy(m_reg_data.data(), src, m_reg_data.size());
error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet);
if (error.Fail())
return error;
return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet);
}
llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom(
NativeRegisterContextFreeBSD &source) {
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
auto &r_source = static_cast<NativeRegisterContextFreeBSD_arm64 &>(source);
llvm::Error error = r_source.ReadHardwareDebugInfo();
if (error)
return error;
m_dbreg = r_source.m_dbreg;
m_hbp_regs = r_source.m_hbp_regs;
m_hwp_regs = r_source.m_hwp_regs;
m_max_hbp_supported = r_source.m_max_hbp_supported;
m_max_hwp_supported = r_source.m_max_hwp_supported;
m_read_dbreg = true;
// on FreeBSD this writes both breakpoints and watchpoints
return WriteHardwareDebugRegs(eDREGTypeWATCH);
#else
return llvm::Error::success();
#endif
}
llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() {
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
// we're fully stateful, so no need to reread control registers ever
if (m_read_dbreg)
return llvm::Error::success();
Status res = NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS,
m_thread.GetID(), &m_dbreg);
if (res.Fail())
return res.ToError();
LLDB_LOG(log, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}",
m_dbreg.db_debug_ver, m_dbreg.db_nbkpts, m_dbreg.db_nwtpts);
m_max_hbp_supported = m_dbreg.db_nbkpts;
m_max_hwp_supported = m_dbreg.db_nwtpts;
assert(m_max_hbp_supported <= m_hbp_regs.size());
assert(m_max_hwp_supported <= m_hwp_regs.size());
m_read_dbreg = true;
return llvm::Error::success();
#else
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Hardware breakpoints/watchpoints require FreeBSD 14.0");
#endif
}
llvm::Error
NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) {
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
assert(m_read_dbreg && "dbregs must be read before writing them back");
// copy data from m_*_regs to m_dbreg before writing it back
for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
m_dbreg.db_breakregs[i].dbr_addr = m_hbp_regs[i].address;
m_dbreg.db_breakregs[i].dbr_ctrl = m_hbp_regs[i].control;
}
for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
m_dbreg.db_watchregs[i].dbw_addr = m_hwp_regs[i].address;
m_dbreg.db_watchregs[i].dbw_ctrl = m_hwp_regs[i].control;
}
return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
&m_dbreg)
.ToError();
#else
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Hardware breakpoints/watchpoints require FreeBSD 14.0");
#endif
}
#endif // defined (__aarch64__)

View File

@ -0,0 +1,86 @@
//===-- NativeRegisterContextFreeBSD_arm64.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
//
//===----------------------------------------------------------------------===//
#if defined(__aarch64__)
#ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
#define lldb_NativeRegisterContextFreeBSD_arm64_h
// clang-format off
#include <sys/types.h>
#include <sys/param.h>
#include <machine/reg.h>
// clang-format on
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include <array>
#if __FreeBSD_version >= 1300139
# define LLDB_HAS_FREEBSD_WATCHPOINT 1
#endif
namespace lldb_private {
namespace process_freebsd {
class NativeProcessFreeBSD;
class NativeRegisterContextFreeBSD_arm64
: public NativeRegisterContextFreeBSD,
public NativeRegisterContextDBReg_arm64 {
public:
NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
private:
// Due to alignment, FreeBSD reg/fpreg are a few bytes larger than
// LLDB's GPR/FPU structs. However, all fields have matching offsets
// and sizes, so we do not have to worry about these (and we have
// a unittest to assert that).
std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
#ifdef LLDB_HAS_FREEBSD_WATCHPOINT
dbreg m_dbreg;
bool m_read_dbreg;
#endif
Status ReadRegisterSet(uint32_t set);
Status WriteRegisterSet(uint32_t set);
llvm::Error ReadHardwareDebugInfo() override;
llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
RegisterInfoPOSIX_arm64 &GetRegisterInfo() const;
};
} // namespace process_freebsd
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm64_h
#endif // defined (__aarch64__)

View File

@ -0,0 +1,186 @@
//===-- NativeRegisterContextFreeBSD_mips64.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
//
//===----------------------------------------------------------------------===//
#if defined(__mips64__)
#include "NativeRegisterContextFreeBSD_mips64.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
// clang-format off
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
// clang-format on
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_freebsd;
NativeRegisterContextFreeBSD *
NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread);
}
NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
: NativeRegisterContextRegisterInfo(
native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {}
RegisterContextFreeBSD_mips64 &
NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const {
return static_cast<RegisterContextFreeBSD_mips64 &>(
*m_register_info_interface_up);
}
uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const {
return GetRegisterInfo().GetRegisterSetCount();
}
const RegisterSet *
NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const {
return GetRegisterInfo().GetRegisterSet(set_index);
}
uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const {
uint32_t count = 0;
for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
count += GetRegisterSet(set_index)->num_registers;
return count;
}
Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
m_reg_data.data());
}
llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet");
}
Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
m_reg_data.data());
}
llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet");
}
Status
NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) {
Status error;
if (!reg_info) {
error.SetErrorString("reg_info NULL");
return error;
}
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
RegSetKind set = GPRegSet;
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
reg_info->byte_size, endian::InlHostByteOrder());
return error;
}
Status NativeRegisterContextFreeBSD_mips64::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &reg_value) {
Status error;
if (!reg_info)
return Status("reg_info NULL");
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
RegSetKind set = GPRegSet;
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
reg_info->byte_size);
return WriteRegisterSet(set);
}
Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues(
lldb::DataBufferSP &data_sp) {
Status error;
error = ReadRegisterSet(GPRegSet);
if (error.Fail())
return error;
data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
uint8_t *dst = data_sp->GetBytes();
::memcpy(dst, m_reg_data.data(), m_reg_data.size());
return error;
}
Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues(
const lldb::DataBufferSP &data_sp) {
Status error;
if (!data_sp) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided",
__FUNCTION__);
return error;
}
if (data_sp->GetByteSize() != m_reg_data.size()) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched "
"data size, expected %" PRIu64 ", actual %" PRIu64,
__FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
return error;
}
uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s "
"DataBuffer::GetBytes() returned a null "
"pointer",
__FUNCTION__);
return error;
}
::memcpy(m_reg_data.data(), src, m_reg_data.size());
return WriteRegisterSet(GPRegSet);
}
llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom(
NativeRegisterContextFreeBSD &source) {
return llvm::Error::success();
}
#endif // defined (__mips64__)

View File

@ -0,0 +1,71 @@
//===-- NativeRegisterContextFreeBSD_mips64.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
//
//===----------------------------------------------------------------------===//
#if defined(__mips64__)
#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
#define lldb_NativeRegisterContextFreeBSD_mips64_h
// clang-format off
#include <sys/types.h>
#include <machine/reg.h>
// clang-format on
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
#include <array>
namespace lldb_private {
namespace process_freebsd {
class NativeProcessFreeBSD;
class NativeRegisterContextFreeBSD_mips64
: public NativeRegisterContextFreeBSD {
public:
NativeRegisterContextFreeBSD_mips64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
private:
enum RegSetKind {
GPRegSet,
};
std::array<uint8_t, sizeof(reg)> m_reg_data;
Status ReadRegisterSet(RegSetKind set);
Status WriteRegisterSet(RegSetKind set);
RegisterContextFreeBSD_mips64 &GetRegisterInfo() const;
};
} // namespace process_freebsd
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h
#endif // defined (__mips64__)

View File

@ -0,0 +1,289 @@
//===-- NativeRegisterContextFreeBSD_powerpc.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
//
//===----------------------------------------------------------------------===//
#if defined(__powerpc__)
#include "NativeRegisterContextFreeBSD_powerpc.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
// for register enum definitions
#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
// clang-format off
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
// clang-format on
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_freebsd;
static const uint32_t g_gpr_regnums[] = {
gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc,
gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc,
gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc,
gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc,
gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc,
gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc,
gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc,
gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc,
gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc,
gpr_pc_powerpc,
};
static const uint32_t g_fpr_regnums[] = {
fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc,
fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc,
fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc,
fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc,
fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc,
fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc,
fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc,
fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc,
fpr_fpscr_powerpc,
};
// Number of register sets provided by this context.
enum { k_num_register_sets = 2 };
static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = {
{"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc,
g_gpr_regnums},
{"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc,
g_fpr_regnums},
};
NativeRegisterContextFreeBSD *
NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread);
}
static RegisterInfoInterface *
CreateRegisterInfoInterface(const ArchSpec &target_arch) {
if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
return new RegisterContextFreeBSD_powerpc32(target_arch);
} else {
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
"Register setting path assumes this is a 64-bit host");
return new RegisterContextFreeBSD_powerpc64(target_arch);
}
}
NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
: NativeRegisterContextRegisterInfo(
native_thread, CreateRegisterInfoInterface(target_arch)) {}
RegisterContextFreeBSD_powerpc &
NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const {
return static_cast<RegisterContextFreeBSD_powerpc &>(
*m_register_info_interface_up);
}
uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const {
return k_num_register_sets;
}
const RegisterSet *
NativeRegisterContextFreeBSD_powerpc::GetRegisterSet(uint32_t set_index) const {
switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
case llvm::Triple::ppc:
return &g_reg_sets_powerpc[set_index];
default:
llvm_unreachable("Unhandled target architecture.");
}
}
llvm::Optional<NativeRegisterContextFreeBSD_powerpc::RegSetKind>
NativeRegisterContextFreeBSD_powerpc::GetSetForNativeRegNum(
uint32_t reg_num) const {
switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
case llvm::Triple::ppc:
if (reg_num >= k_first_gpr_powerpc && reg_num <= k_last_gpr_powerpc)
return GPRegSet;
if (reg_num >= k_first_fpr && reg_num <= k_last_fpr)
return FPRegSet;
break;
default:
llvm_unreachable("Unhandled target architecture.");
}
llvm_unreachable("Register does not belong to any register set");
}
uint32_t NativeRegisterContextFreeBSD_powerpc::GetUserRegisterCount() const {
uint32_t count = 0;
for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index)
count += GetRegisterSet(set_index)->num_registers;
return count;
}
Status NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
m_reg_data.data());
case FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(reg));
}
llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet");
}
Status NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
m_reg_data.data());
case FPRegSet:
return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
m_reg_data.data() + sizeof(reg));
}
llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet");
}
Status
NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) {
Status error;
if (!reg_info) {
error.SetErrorString("reg_info NULL");
return error;
}
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
if (!opt_set) {
// This is likely an internal register for lldb use only and should not be
// directly queried.
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
reg_info->name);
return error;
}
RegSetKind set = opt_set.getValue();
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset,
reg_info->byte_size, endian::InlHostByteOrder());
return error;
}
Status NativeRegisterContextFreeBSD_powerpc::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &reg_value) {
Status error;
if (!reg_info)
return Status("reg_info NULL");
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (reg == LLDB_INVALID_REGNUM)
return Status("no lldb regnum for %s", reg_info && reg_info->name
? reg_info->name
: "<unknown register>");
llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
if (!opt_set) {
// This is likely an internal register for lldb use only and should not be
// directly queried.
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
reg_info->name);
return error;
}
RegSetKind set = opt_set.getValue();
error = ReadRegisterSet(set);
if (error.Fail())
return error;
assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size());
::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(),
reg_info->byte_size);
return WriteRegisterSet(set);
}
Status NativeRegisterContextFreeBSD_powerpc::ReadAllRegisterValues(
lldb::DataBufferSP &data_sp) {
Status error;
error = ReadRegisterSet(GPRegSet);
if (error.Fail())
return error;
error = ReadRegisterSet(FPRegSet);
if (error.Fail())
return error;
data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0));
uint8_t *dst = data_sp->GetBytes();
::memcpy(dst, m_reg_data.data(), m_reg_data.size());
return error;
}
Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues(
const lldb::DataBufferSP &data_sp) {
Status error;
if (!data_sp) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_powerpc::%s invalid data_sp provided",
__FUNCTION__);
return error;
}
if (data_sp->GetByteSize() != m_reg_data.size()) {
error.SetErrorStringWithFormat(
"NativeRegisterContextFreeBSD_powerpc::%s data_sp contained mismatched "
"data size, expected %zu, actual %" PRIu64,
__FUNCTION__, m_reg_data.size(), data_sp->GetByteSize());
return error;
}
uint8_t *src = data_sp->GetBytes();
if (src == nullptr) {
error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s "
"DataBuffer::GetBytes() returned a null "
"pointer",
__FUNCTION__);
return error;
}
::memcpy(m_reg_data.data(), src, m_reg_data.size());
error = WriteRegisterSet(GPRegSet);
if (error.Fail())
return error;
return WriteRegisterSet(FPRegSet);
}
llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom(
NativeRegisterContextFreeBSD &source) {
return llvm::Error::success();
}
#endif // defined (__powerpc__)

View File

@ -0,0 +1,74 @@
//===-- NativeRegisterContextFreeBSD_powerpc.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
//
//===----------------------------------------------------------------------===//
#if defined(__powerpc__)
#ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h
#define lldb_NativeRegisterContextFreeBSD_powerpc_h
// clang-format off
#include <sys/types.h>
#include <machine/reg.h>
// clang-format on
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
#include <array>
namespace lldb_private {
namespace process_freebsd {
class NativeProcessFreeBSD;
class NativeRegisterContextFreeBSD_powerpc
: public NativeRegisterContextFreeBSD {
public:
NativeRegisterContextFreeBSD_powerpc(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
uint32_t GetRegisterSetCount() const override;
uint32_t GetUserRegisterCount() const override;
const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;
Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;
Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
private:
enum RegSetKind {
GPRegSet,
FPRegSet,
};
std::array<uint8_t, sizeof(reg) + sizeof(fpreg)> m_reg_data;
llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
Status ReadRegisterSet(RegSetKind set);
Status WriteRegisterSet(RegSetKind set);
RegisterContextFreeBSD_powerpc &GetRegisterInfo() const;
};
} // namespace process_freebsd
} // namespace lldb_private
#endif // #ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h
#endif // defined (__powerpc__)

View File

@ -20,9 +20,9 @@
#include <array>
#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/Utility/RegisterContext_x86.h"
#include "Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h"
#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX
@ -34,7 +34,7 @@ class NativeProcessFreeBSD;
class NativeRegisterContextFreeBSD_x86_64
: public NativeRegisterContextFreeBSD,
public NativeRegisterContextWatchpoint_x86 {
public NativeRegisterContextDBReg_x86 {
public:
NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);

View File

@ -46,6 +46,11 @@ Status NativeThreadFreeBSD::Resume() {
if (!ret.Success())
return ret;
ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
// we can get EINVAL if the architecture in question does not support
// hardware single-stepping -- that's fine, we have nothing to clear
// then
if (ret.GetError() == EINVAL)
ret.Clear();
if (ret.Success())
SetRunning();
return ret;

View File

@ -11,7 +11,7 @@
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h"
#include <csignal>
#include <map>

View File

@ -1,44 +0,0 @@
//===-- POSIXStopInfo.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
//
//===----------------------------------------------------------------------===//
#include "POSIXStopInfo.h"
using namespace lldb;
using namespace lldb_private;
//===----------------------------------------------------------------------===//
// POSIXLimboStopInfo
POSIXLimboStopInfo::~POSIXLimboStopInfo() {}
lldb::StopReason POSIXLimboStopInfo::GetStopReason() const {
return lldb::eStopReasonThreadExiting;
}
const char *POSIXLimboStopInfo::GetDescription() { return "thread exiting"; }
bool POSIXLimboStopInfo::ShouldStop(Event *event_ptr) { return false; }
bool POSIXLimboStopInfo::ShouldNotify(Event *event_ptr) { return false; }
//===----------------------------------------------------------------------===//
// POSIXNewThreadStopInfo
POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() {}
lldb::StopReason POSIXNewThreadStopInfo::GetStopReason() const {
return lldb::eStopReasonNone;
}
const char *POSIXNewThreadStopInfo::GetDescription() {
return "thread spawned";
}
bool POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr) { return false; }
bool POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr) { return false; }

View File

@ -1,66 +0,0 @@
//===-- POSIXStopInfo.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_POSIXStopInfo_H_
#define liblldb_POSIXStopInfo_H_
#include "FreeBSDThread.h"
#include "Plugins/Process/POSIX/CrashReason.h"
#include "lldb/Target/StopInfo.h"
#include <string>
//===----------------------------------------------------------------------===//
/// \class POSIXStopInfo
/// Simple base class for all POSIX-specific StopInfo objects.
///
class POSIXStopInfo : public lldb_private::StopInfo {
public:
POSIXStopInfo(lldb_private::Thread &thread, uint32_t status)
: StopInfo(thread, status) {}
};
//===----------------------------------------------------------------------===//
/// \class POSIXLimboStopInfo
/// Represents the stop state of a process ready to exit.
///
class POSIXLimboStopInfo : public POSIXStopInfo {
public:
POSIXLimboStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {}
~POSIXLimboStopInfo();
lldb::StopReason GetStopReason() const override;
const char *GetDescription() override;
bool ShouldStop(lldb_private::Event *event_ptr) override;
bool ShouldNotify(lldb_private::Event *event_ptr) override;
};
//===----------------------------------------------------------------------===//
/// \class POSIXNewThreadStopInfo
/// Represents the stop state of process when a new thread is spawned.
///
class POSIXNewThreadStopInfo : public POSIXStopInfo {
public:
POSIXNewThreadStopInfo(FreeBSDThread &thread) : POSIXStopInfo(thread, 0) {}
~POSIXNewThreadStopInfo();
lldb::StopReason GetStopReason() const override;
const char *GetDescription() override;
bool ShouldStop(lldb_private::Event *event_ptr) override;
bool ShouldNotify(lldb_private::Event *event_ptr) override;
};
#endif

View File

@ -1,221 +0,0 @@
//===-- ProcessFreeBSD.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ProcessFreeBSD_H_
#define liblldb_ProcessFreeBSD_H_
#include "Plugins/Process/POSIX/ProcessMessage.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/ThreadList.h"
#include <mutex>
#include <queue>
#include <set>
class ProcessMonitor;
class FreeBSDThread;
class ProcessFreeBSD : public lldb_private::Process {
public:
// Static functions.
static lldb::ProcessSP
CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
const lldb_private::FileSpec *crash_file_path,
bool can_connect);
static void Initialize();
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
// Constructors and destructors
ProcessFreeBSD(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
lldb::UnixSignalsSP &unix_signals_sp);
~ProcessFreeBSD();
virtual lldb_private::Status WillResume() override;
// PluginInterface protocol
virtual lldb_private::ConstString GetPluginName() override;
virtual uint32_t GetPluginVersion() override;
public:
// Process protocol.
void Finalize() override;
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
lldb_private::Status WillLaunch(lldb_private::Module *module) override;
lldb_private::Status DoAttachToProcessWithID(
lldb::pid_t pid,
const lldb_private::ProcessAttachInfo &attach_info) override;
lldb_private::Status
DoLaunch(lldb_private::Module *exe_module,
lldb_private::ProcessLaunchInfo &launch_info) override;
void DidLaunch() override;
lldb_private::Status DoResume() override;
lldb_private::Status DoHalt(bool &caused_stop) override;
lldb_private::Status DoDetach(bool keep_stopped) override;
lldb_private::Status DoSignal(int signal) override;
lldb_private::Status DoDestroy() override;
void DoDidExec() override;
void RefreshStateAfterStop() override;
bool IsAlive() override;
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
lldb_private::Status &error) override;
size_t DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
lldb_private::Status &error) override;
lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
lldb_private::Status &error) override;
lldb_private::Status DoDeallocateMemory(lldb::addr_t ptr) override;
virtual size_t
GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite *bp_site);
lldb_private::Status
EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
lldb_private::Status
DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp,
bool notify = true) override;
lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp,
bool notify = true) override;
lldb_private::Status GetWatchpointSupportInfo(uint32_t &num) override;
lldb_private::Status GetWatchpointSupportInfo(uint32_t &num,
bool &after) override;
virtual uint32_t UpdateThreadListIfNeeded();
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
lldb_private::ThreadList &new_thread_list) override;
virtual lldb::ByteOrder GetByteOrder() const;
lldb::addr_t GetImageInfoAddress() override;
size_t PutSTDIN(const char *buf, size_t len,
lldb_private::Status &error) override;
lldb_private::DataExtractor GetAuxvData() override;
// ProcessFreeBSD internal API.
/// Registers the given message with this process.
virtual void SendMessage(const ProcessMessage &message);
ProcessMonitor &GetMonitor() {
assert(m_monitor);
return *m_monitor;
}
lldb_private::FileSpec
GetFileSpec(const lldb_private::FileAction *file_action,
const lldb_private::FileSpec &default_file_spec,
const lldb_private::FileSpec &dbg_pts_file_spec);
/// Adds the thread to the list of threads for which we have received the
/// initial stopping signal.
/// The \p stop_tid parameter indicates the thread which the stop happened
/// for.
bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
bool WaitingForInitialStop(lldb::tid_t stop_tid);
virtual FreeBSDThread *CreateNewFreeBSDThread(lldb_private::Process &process,
lldb::tid_t tid);
static bool SingleStepBreakpointHit(
void *baton, lldb_private::StoppointCallbackContext *context,
lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
lldb_private::Status SetupSoftwareSingleStepping(lldb::tid_t tid);
lldb_private::Status SetSoftwareSingleStepBreakpoint(lldb::tid_t tid,
lldb::addr_t addr);
bool IsSoftwareStepBreakpoint(lldb::tid_t tid);
bool SupportHardwareSingleStepping() const;
typedef std::vector<lldb::tid_t> tid_collection;
tid_collection &GetStepTids() { return m_step_tids; }
protected:
static const size_t MAX_TRAP_OPCODE_SIZE = 8;
/// Target byte order.
lldb::ByteOrder m_byte_order;
/// Process monitor;
ProcessMonitor *m_monitor;
/// The module we are executing.
lldb_private::Module *m_module;
/// Message queue notifying this instance of inferior process state changes.
std::recursive_mutex m_message_mutex;
std::queue<ProcessMessage> m_message_queue;
/// Drive any exit events to completion.
bool m_exit_now;
/// Returns true if the process has exited.
bool HasExited();
/// Returns true if the process is stopped.
bool IsStopped();
/// Returns true if at least one running is currently running
bool IsAThreadRunning();
typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
MMapMap m_addr_to_mmap_size;
typedef std::set<lldb::tid_t> ThreadStopSet;
/// Every thread begins with a stop signal. This keeps track
/// of the threads for which we have received the stop signal.
ThreadStopSet m_seen_initial_stop;
friend class FreeBSDThread;
tid_collection m_suspend_tids;
tid_collection m_run_tids;
tid_collection m_step_tids;
std::map<lldb::tid_t, lldb::break_id_t> m_threads_stepping_with_breakpoint;
int m_resume_signo;
};
#endif // liblldb_ProcessFreeBSD_H_

View File

@ -1,279 +0,0 @@
//===-- ProcessMonitor.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ProcessMonitor_H_
#define liblldb_ProcessMonitor_H_
#include <semaphore.h>
#include <signal.h>
#include <mutex>
#include "lldb/Host/HostThread.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/lldb-types.h"
namespace lldb_private {
class Status;
class Module;
class Scalar;
} // End lldb_private namespace.
class ProcessFreeBSD;
class Operation;
/// \class ProcessMonitor
/// Manages communication with the inferior (debugee) process.
///
/// Upon construction, this class prepares and launches an inferior process
/// for debugging.
///
/// Changes in the inferior process state are propagated to the associated
/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the
/// appropriate ProcessMessage events.
///
/// A purposely minimal set of operations are provided to interrogate and change
/// the inferior process state.
class ProcessMonitor {
public:
/// Launches an inferior process ready for debugging. Forms the
/// implementation of Process::DoLaunch.
ProcessMonitor(ProcessFreeBSD *process, lldb_private::Module *module,
char const *argv[], lldb_private::Environment env,
const lldb_private::FileSpec &stdin_file_spec,
const lldb_private::FileSpec &stdout_file_spec,
const lldb_private::FileSpec &stderr_file_spec,
const lldb_private::FileSpec &working_dir,
const lldb_private::ProcessLaunchInfo &launch_info,
lldb_private::Status &error);
ProcessMonitor(ProcessFreeBSD *process, lldb::pid_t pid,
lldb_private::Status &error);
~ProcessMonitor();
/// Provides the process number of debugee.
lldb::pid_t GetPID() const { return m_pid; }
/// Returns the process associated with this ProcessMonitor.
ProcessFreeBSD &GetProcess() { return *m_process; }
/// Returns a file descriptor to the controlling terminal of the inferior
/// process.
///
/// Reads from this file descriptor yield both the standard output and
/// standard error of this debugee. Even if stderr and stdout were
/// redirected on launch it may still happen that data is available on this
/// descriptor (if the inferior process opens /dev/tty, for example). This
/// descriptor is closed after a call to StopMonitor().
///
/// If this monitor was attached to an existing process this method returns
/// -1.
int GetTerminalFD() const { return m_terminal_fd; }
/// Reads \p size bytes from address @vm_adder in the inferior process
/// address space.
///
/// This method is provided to implement Process::DoReadMemory.
size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
lldb_private::Status &error);
/// Writes \p size bytes from address \p vm_adder in the inferior process
/// address space.
///
/// This method is provided to implement Process::DoWriteMemory.
size_t WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
lldb_private::Status &error);
/// Reads the contents from the register identified by the given
/// (architecture dependent) offset.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
unsigned size, lldb_private::RegisterValue &value);
/// Writes the given value to the register identified by the given
/// (architecture dependent) offset.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool WriteRegisterValue(lldb::tid_t tid, unsigned offset,
const char *reg_name,
const lldb_private::RegisterValue &value);
/// Reads the contents from the debug register identified by the given
/// (architecture dependent) offset.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset,
const char *reg_name, unsigned size,
lldb_private::RegisterValue &value);
/// Writes the given value to the debug register identified by the given
/// (architecture dependent) offset.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset,
const char *reg_name,
const lldb_private::RegisterValue &value);
/// Reads all general purpose registers into the specified buffer.
bool ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
/// Reads all floating point registers into the specified buffer.
bool ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
/// Reads the specified register set into the specified buffer.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size,
unsigned int regset);
/// Writes all general purpose registers into the specified buffer.
bool WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
/// Writes all floating point registers into the specified buffer.
bool WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
/// Writes the specified register set into the specified buffer.
///
/// This method is provided for use by RegisterContextFreeBSD derivatives.
bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size,
unsigned int regset);
/// Reads the value of the thread-specific pointer for a given thread ID.
bool ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value);
/// Returns current thread IDs in process
size_t GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids);
/// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
/// to the memory region pointed to by \p lwpinfo.
bool GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
/// Suspends or unsuspends a thread prior to process resume or step.
bool ThreadSuspend(lldb::tid_t tid, bool suspend);
/// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
/// corresponding to the given thread IDto the memory pointed to by @p
/// message.
bool GetEventMessage(lldb::tid_t tid, unsigned long *message);
/// Resumes the process. If \p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
bool Resume(lldb::tid_t unused, uint32_t signo);
/// Single steps the process. If \p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
bool SingleStep(lldb::tid_t unused, uint32_t signo);
/// Terminate the traced process.
bool Kill();
lldb_private::Status Detach(lldb::tid_t tid);
void StopMonitor();
// Waits for the initial stop message from a new thread.
bool WaitForInitialTIDStop(lldb::tid_t tid);
private:
ProcessFreeBSD *m_process;
llvm::Optional<lldb_private::HostThread> m_operation_thread;
llvm::Optional<lldb_private::HostThread> m_monitor_thread;
lldb::pid_t m_pid;
int m_terminal_fd;
// current operation which must be executed on the privileged thread
Operation *m_operation;
std::mutex m_operation_mutex;
// semaphores notified when Operation is ready to be processed and when
// the operation is complete.
sem_t m_operation_pending;
sem_t m_operation_done;
struct OperationArgs {
OperationArgs(ProcessMonitor *monitor);
~OperationArgs();
ProcessMonitor *m_monitor; // The monitor performing the attach.
sem_t m_semaphore; // Posted to once operation complete.
lldb_private::Status m_error; // Set if process operation failed.
};
/// \class LauchArgs
///
/// Simple structure to pass data to the thread responsible for launching a
/// child process.
struct LaunchArgs : OperationArgs {
LaunchArgs(ProcessMonitor *monitor, lldb_private::Module *module,
char const **argv, lldb_private::Environment env,
const lldb_private::FileSpec &stdin_file_spec,
const lldb_private::FileSpec &stdout_file_spec,
const lldb_private::FileSpec &stderr_file_spec,
const lldb_private::FileSpec &working_dir);
~LaunchArgs();
lldb_private::Module *m_module; // The executable image to launch.
char const **m_argv; // Process arguments.
lldb_private::Environment m_env; // Process environment.
const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty.
const lldb_private::FileSpec
m_stdout_file_spec; // Redirect stdout or empty.
const lldb_private::FileSpec
m_stderr_file_spec; // Redirect stderr or empty.
const lldb_private::FileSpec m_working_dir; // Working directory or empty.
};
void StartLaunchOpThread(LaunchArgs *args, lldb_private::Status &error);
static void *LaunchOpThread(void *arg);
static bool Launch(LaunchArgs *args);
struct AttachArgs : OperationArgs {
AttachArgs(ProcessMonitor *monitor, lldb::pid_t pid);
~AttachArgs();
lldb::pid_t m_pid; // pid of the process to be attached.
};
void StartAttachOpThread(AttachArgs *args, lldb_private::Status &error);
static void *AttachOpThread(void *args);
static void Attach(AttachArgs *args);
static void ServeOperation(OperationArgs *args);
static bool DupDescriptor(const lldb_private::FileSpec &file_spec, int fd,
int flags);
static bool MonitorCallback(ProcessMonitor *monitor, lldb::pid_t pid,
bool exited, int signal, int status);
static ProcessMessage MonitorSIGTRAP(ProcessMonitor *monitor,
const siginfo_t *info, lldb::pid_t pid);
static ProcessMessage MonitorSignal(ProcessMonitor *monitor,
const siginfo_t *info, lldb::pid_t pid);
void DoOperation(Operation *op);
/// Stops the child monitor thread.
void StopMonitoringChildProcess();
/// Stops the operation thread used to attach/launch a process.
void StopOpThread();
};
#endif // #ifndef liblldb_ProcessMonitor_H_

View File

@ -1,63 +0,0 @@
//===-- RegisterContextPOSIX.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIX_H_
#define liblldb_RegisterContextPOSIX_H_
#include "Plugins/Process/Utility/RegisterInfoInterface.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/ArchSpec.h"
/// \class POSIXBreakpointProtocol
///
/// Extends RegisterClass with a few virtual operations useful on POSIX.
class POSIXBreakpointProtocol {
public:
POSIXBreakpointProtocol() { m_watchpoints_initialized = false; }
virtual ~POSIXBreakpointProtocol() {}
/// Updates the register state of the associated thread after hitting a
/// breakpoint (if that make sense for the architecture). Default
/// implementation simply returns true for architectures which do not
/// require any update.
///
/// \return
/// True if the operation succeeded and false otherwise.
virtual bool UpdateAfterBreakpoint() = 0;
/// Determines the index in lldb's register file given a kernel byte offset.
virtual unsigned GetRegisterIndexFromOffset(unsigned offset) = 0;
// Checks to see if a watchpoint specified by hw_index caused the inferior
// to stop.
virtual bool IsWatchpointHit(uint32_t hw_index) = 0;
// Resets any watchpoints that have been hit.
virtual bool ClearWatchpointHits() = 0;
// Returns the watchpoint address associated with a watchpoint hardware
// index.
virtual lldb::addr_t GetWatchpointAddress(uint32_t hw_index) = 0;
virtual bool IsWatchpointVacant(uint32_t hw_index) = 0;
virtual bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
bool read, bool write,
uint32_t hw_index) = 0;
// From lldb_private::RegisterContext
virtual uint32_t NumSupportedHardwareWatchpoints() = 0;
// Force m_watchpoints_initialized to TRUE
void ForceWatchpointsInitialized() { m_watchpoints_initialized = true; }
protected:
bool m_watchpoints_initialized;
};
#endif // #ifndef liblldb_RegisterContextPOSIX_H_

View File

@ -1,260 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_arm.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
//
//===---------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
using namespace lldb_private;
using namespace lldb;
#define REG_CONTEXT_SIZE (GetGPRSize())
RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm> register_info)
: RegisterContextPOSIX_arm(thread, std::move(register_info)) {}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm::GetMonitor() {
ProcessSP base = CalculateProcess();
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get());
return process->GetMonitor();
}
bool RegisterContextPOSIXProcessMonitor_arm::ReadGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_arm::ReadFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
}
bool RegisterContextPOSIXProcessMonitor_arm::WriteGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_arm::WriteFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
}
bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister(
const unsigned reg, RegisterValue &value) {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg),
GetRegisterName(reg), GetRegisterSize(reg),
value);
}
bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister(
const unsigned reg, const RegisterValue &value) {
unsigned reg_to_write = reg;
RegisterValue value_to_write = value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = value.GetAsMemoryData(
reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
}
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteRegisterValue(
m_thread.GetID(), GetRegisterOffset(reg_to_write),
GetRegisterName(reg_to_write), value_to_write);
}
bool RegisterContextPOSIXProcessMonitor_arm::ReadRegister(
const RegisterInfo *reg_info, RegisterValue &value) {
if (!reg_info)
return false;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsFPR(reg)) {
if (!ReadFPR())
return false;
} else {
return ReadRegister(reg, value);
}
// Get pointer to m_fpr variable and set the data from it.
assert(reg_info->byte_offset < sizeof m_fpr);
uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
switch (reg_info->byte_size) {
case 2:
value.SetUInt16(*(uint16_t *)src);
return true;
case 4:
value.SetUInt32(*(uint32_t *)src);
return true;
case 8:
value.SetUInt64(*(uint64_t *)src);
return true;
default:
assert(false && "Unhandled data size.");
return false;
}
}
bool RegisterContextPOSIXProcessMonitor_arm::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &value) {
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsGPR(reg)) {
return WriteRegister(reg, value);
} else if (IsFPR(reg)) {
return WriteFPR();
}
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(
DataBufferSP &data_sp) {
bool success = false;
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
if (ReadGPR() && ReadFPR()) {
uint8_t *dst = data_sp->GetBytes();
success = dst != 0;
if (success) {
::memcpy(dst, &m_gpr_arm, GetGPRSize());
dst += GetGPRSize();
::memcpy(dst, &m_fpr, sizeof(m_fpr));
}
}
return success;
}
bool RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(
const DataBufferSP &data_sp) {
bool success = false;
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
uint8_t *src = data_sp->GetBytes();
if (src) {
::memcpy(&m_gpr_arm, src, GetGPRSize());
if (WriteGPR()) {
src += GetGPRSize();
::memcpy(&m_fpr, src, sizeof(m_fpr));
success = WriteFPR();
}
}
}
return success;
}
uint32_t RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(
addr_t addr, size_t size, bool read, bool write) {
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
uint32_t hw_index;
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) {
if (IsWatchpointVacant(hw_index))
return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index);
}
return LLDB_INVALID_INDEX32;
}
bool RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint() {
lldb::addr_t pc;
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
return false;
return true;
}
unsigned RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(
unsigned offset) {
unsigned reg;
for (reg = 0; reg < k_num_registers_arm; reg++) {
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
assert(reg < k_num_registers_arm && "Invalid register offset.");
return reg;
}
bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits() {
return false;
}
addr_t RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(
uint32_t hw_index) {
return LLDB_INVALID_ADDRESS;
}
bool RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(
addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) {
return false;
}
uint32_t
RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints() {
return 0;
}

View File

@ -1,80 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_arm.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
#include "RegisterContextPOSIX.h"
class RegisterContextPOSIXProcessMonitor_arm : public RegisterContextPOSIX_arm,
public POSIXBreakpointProtocol {
public:
RegisterContextPOSIXProcessMonitor_arm(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm> register_info);
protected:
bool ReadGPR() override;
bool ReadFPR() override;
bool WriteGPR() override;
bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
bool WriteRegister(const unsigned reg,
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) override;
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
bool write) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
bool UpdateAfterBreakpoint() override;
unsigned GetRegisterIndexFromOffset(unsigned offset) override;
bool IsWatchpointHit(uint32_t hw_index) override;
bool ClearWatchpointHits() override;
lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
bool write, uint32_t hw_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
private:
RegisterInfoPOSIX_arm::GPR m_gpr_arm;
RegisterInfoPOSIX_arm::FPU m_fpr;
ProcessMonitor &GetMonitor();
};
#endif

View File

@ -1,267 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_arm64.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
//
//===---------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm64.h"
#define REG_CONTEXT_SIZE (GetGPRSize())
using namespace lldb;
using namespace lldb_private;
RegisterContextPOSIXProcessMonitor_arm64::
RegisterContextPOSIXProcessMonitor_arm64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info)
: RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
::memset(&m_gpr_arm64, 0, sizeof m_gpr_arm64);
::memset(&m_fpr, 0, sizeof m_fpr);
}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() {
lldb::ProcessSP base = CalculateProcess();
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get());
return process->GetMonitor();
}
bool RegisterContextPOSIXProcessMonitor_arm64::ReadGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_arm64::ReadFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
}
bool RegisterContextPOSIXProcessMonitor_arm64::WriteGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_arm64::WriteFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
}
bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(
const unsigned reg, lldb_private::RegisterValue &value) {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg),
GetRegisterName(reg), GetRegisterSize(reg),
value);
}
bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(
const unsigned reg, const lldb_private::RegisterValue &value) {
unsigned reg_to_write = reg;
lldb_private::RegisterValue value_to_write = value;
// Check if this is a subregister of a full register.
const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
lldb_private::RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const lldb_private::RegisterInfo *full_reg_info =
GetRegisterInfoAtIndex(full_reg);
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
lldb_private::Status error;
lldb::ByteOrder byte_order = GetByteOrder();
uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = value.GetAsMemoryData(
reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
::memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
}
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteRegisterValue(
m_thread.GetID(), GetRegisterOffset(reg_to_write),
GetRegisterName(reg_to_write), value_to_write);
}
bool RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(
const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) {
if (!reg_info)
return false;
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (IsFPR(reg)) {
if (!ReadFPR())
return false;
} else {
uint32_t full_reg = reg;
bool is_subreg = reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
if (is_subreg) {
// Read the full aligned 64-bit register.
full_reg = reg_info->invalidate_regs[0];
}
return ReadRegister(full_reg, value);
}
// Get pointer to m_fpr variable and set the data from it.
assert(reg_info->byte_offset < sizeof m_fpr);
uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
switch (reg_info->byte_size) {
case 2:
value.SetUInt16(*(uint16_t *)src);
return true;
case 4:
value.SetUInt32(*(uint32_t *)src);
return true;
case 8:
value.SetUInt64(*(uint64_t *)src);
return true;
default:
assert(false && "Unhandled data size.");
return false;
}
}
bool RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(
const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) {
const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
if (IsGPR(reg))
return WriteRegister(reg, value);
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(
lldb::DataBufferSP &data_sp) {
bool success = false;
data_sp.reset(new lldb_private::DataBufferHeap(REG_CONTEXT_SIZE, 0));
if (ReadGPR() && ReadFPR()) {
uint8_t *dst = data_sp->GetBytes();
success = dst != 0;
if (success) {
::memcpy(dst, &m_gpr_arm64, GetGPRSize());
dst += GetGPRSize();
::memcpy(dst, &m_fpr, sizeof m_fpr);
}
}
return success;
}
bool RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(
const lldb::DataBufferSP &data_sp) {
bool success = false;
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
uint8_t *src = data_sp->GetBytes();
if (src) {
::memcpy(&m_gpr_arm64, src, GetGPRSize());
if (WriteGPR()) {
src += GetGPRSize();
::memcpy(&m_fpr, src, sizeof m_fpr);
success = WriteFPR();
}
}
}
return success;
}
uint32_t RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(
lldb::addr_t addr, size_t size, bool read, bool write) {
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
uint32_t hw_index;
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) {
if (IsWatchpointVacant(hw_index))
return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index);
}
return LLDB_INVALID_INDEX32;
}
bool RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() {
if (GetPC() == LLDB_INVALID_ADDRESS)
return false;
return true;
}
unsigned RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(
unsigned offset) {
unsigned reg;
for (reg = 0; reg < GetRegisterCount(); reg++) {
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
assert(reg < GetRegisterCount() && "Invalid register offset.");
return reg;
}
bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits() {
return false;
}
lldb::addr_t RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(
uint32_t hw_index) {
return LLDB_INVALID_ADDRESS;
}
bool RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(
lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) {
return false;
}
uint32_t
RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints() {
return 0;
}

View File

@ -1,82 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_arm64.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
#include "RegisterContextPOSIX.h"
class RegisterContextPOSIXProcessMonitor_arm64
: public RegisterContextPOSIX_arm64,
public POSIXBreakpointProtocol {
public:
RegisterContextPOSIXProcessMonitor_arm64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info);
protected:
bool ReadGPR() override;
bool ReadFPR() override;
bool WriteGPR() override;
bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
bool WriteRegister(const unsigned reg,
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) override;
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
bool write) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
bool UpdateAfterBreakpoint() override;
unsigned GetRegisterIndexFromOffset(unsigned offset) override;
bool IsWatchpointHit(uint32_t hw_index) override;
bool ClearWatchpointHits() override;
lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
bool write, uint32_t hw_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
private:
RegisterInfoPOSIX_arm64::GPR m_gpr_arm64; // 64-bit general purpose registers.
RegisterInfoPOSIX_arm64::FPU
m_fpr; // floating-point registers including extended register sets.
ProcessMonitor &GetMonitor();
};
#endif

View File

@ -1,262 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_mips64.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
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_mips64.h"
using namespace lldb_private;
using namespace lldb;
#define REG_CONTEXT_SIZE (GetGPRSize())
RegisterContextPOSIXProcessMonitor_mips64::
RegisterContextPOSIXProcessMonitor_mips64(
Thread &thread, uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info)
: RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info) {}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_mips64::GetMonitor() {
ProcessSP base = CalculateProcess();
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get());
return process->GetMonitor();
}
bool RegisterContextPOSIXProcessMonitor_mips64::ReadGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_mips64::ReadFPR() {
// XXX not yet implemented
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::WriteGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_mips64::WriteFPR() {
// XXX not yet implemented
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(
const unsigned reg, RegisterValue &value) {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg),
GetRegisterName(reg), GetRegisterSize(reg),
value);
}
bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(
const unsigned reg, const RegisterValue &value) {
unsigned reg_to_write = reg;
RegisterValue value_to_write = value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = value.GetAsMemoryData(
reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
}
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteRegisterValue(
m_thread.GetID(), GetRegisterOffset(reg_to_write),
GetRegisterName(reg_to_write), value_to_write);
}
bool RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(
const RegisterInfo *reg_info, RegisterValue &value) {
if (!reg_info)
return false;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsFPR(reg)) {
if (!ReadFPR())
return false;
} else {
uint32_t full_reg = reg;
bool is_subreg = reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
if (is_subreg) {
// Read the full aligned 64-bit register.
full_reg = reg_info->invalidate_regs[0];
}
bool success = ReadRegister(full_reg, value);
if (success) {
// If our read was not aligned (for ah,bh,ch,dh), shift our returned
// value one byte to the right.
if (is_subreg && (reg_info->byte_offset & 0x1))
value.SetUInt64(value.GetAsUInt64() >> 8);
// If our return byte size was greater than the return value reg size,
// then use the type specified by reg_info rather than the uint64_t
// default
if (value.GetByteSize() > reg_info->byte_size)
value.SetType(reg_info);
}
return success;
}
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &value) {
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsGPR(reg))
return WriteRegister(reg, value);
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(
DataBufferSP &data_sp) {
bool success = false;
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
if (ReadGPR() && ReadFPR()) {
uint8_t *dst = data_sp->GetBytes();
success = dst != 0;
if (success) {
::memcpy(dst, &m_gpr_mips64, GetGPRSize());
}
}
return success;
}
bool RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(
const DataBufferSP &data_sp) {
bool success = false;
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
uint8_t *src = data_sp->GetBytes();
if (src) {
::memcpy(&m_gpr_mips64, src, GetGPRSize());
if (WriteGPR()) {
src += GetGPRSize();
}
}
}
return success;
}
uint32_t RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(
addr_t addr, size_t size, bool read, bool write) {
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
uint32_t hw_index;
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) {
if (IsWatchpointVacant(hw_index))
return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index);
}
return LLDB_INVALID_INDEX32;
}
bool RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(
bool enable) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint() {
// PC points one byte past the int3 responsible for the breakpoint.
lldb::addr_t pc;
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
return false;
SetPC(pc - 1);
return true;
}
unsigned RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(
unsigned offset) {
unsigned reg;
for (reg = 0; reg < k_num_registers_mips64; reg++) {
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
assert(reg < k_num_registers_mips64 && "Invalid register offset.");
return reg;
}
bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits() {
return false;
}
addr_t RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(
uint32_t hw_index) {
return LLDB_INVALID_ADDRESS;
}
bool RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(
addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) {
return false;
}
uint32_t
RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints() {
return 0;
}

View File

@ -1,82 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_mips64.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
#include "RegisterContextPOSIX.h"
class ProcessMonitor;
class RegisterContextPOSIXProcessMonitor_mips64
: public RegisterContextPOSIX_mips64,
public POSIXBreakpointProtocol {
public:
RegisterContextPOSIXProcessMonitor_mips64(
lldb_private::Thread &thread, uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info);
protected:
bool ReadGPR() override;
bool ReadFPR() override;
bool WriteGPR() override;
bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
bool WriteRegister(const unsigned reg,
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) override;
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
bool write) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
bool UpdateAfterBreakpoint() override;
unsigned GetRegisterIndexFromOffset(unsigned offset) override;
bool IsWatchpointHit(uint32_t hw_index) override;
bool ClearWatchpointHits() override;
lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
bool write, uint32_t hw_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
private:
uint64_t
m_gpr_mips64[lldb_private::k_num_gpr_registers_mips64]; // general purpose registers.
ProcessMonitor &GetMonitor();
};
#endif

View File

@ -1,274 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_powerpc.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
//
//===----------------------------------------------------------------------===//
#include "lldb/Target/Thread.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/RegisterValue.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
using namespace lldb_private;
using namespace lldb;
#define REG_CONTEXT_SIZE (GetGPRSize())
RegisterContextPOSIXProcessMonitor_powerpc::
RegisterContextPOSIXProcessMonitor_powerpc(
Thread &thread, uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info)
: RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info) {}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor() {
ProcessSP base = CalculateProcess();
ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(base.get());
return process->GetMonitor();
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc,
sizeof(m_fpr_powerpc));
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX() {
// XXX: Need a way to read/write process VMX registers with ptrace.
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR() {
ProcessMonitor &monitor = GetMonitor();
return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc,
sizeof(m_fpr_powerpc));
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX() {
// XXX: Need a way to read/write process VMX registers with ptrace.
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(
const unsigned reg, RegisterValue &value) {
ProcessMonitor &monitor = GetMonitor();
return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg),
GetRegisterName(reg), GetRegisterSize(reg),
value);
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(
const unsigned reg, const RegisterValue &value) {
unsigned reg_to_write = reg;
RegisterValue value_to_write = value;
// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
// Read the full register.
if (ReadRegister(full_reg_info, full_value)) {
Status error;
ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Get the bytes for the source data.
const uint32_t src_size = value.GetAsMemoryData(
reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(full_reg_info);
reg_to_write = full_reg;
}
}
}
}
ProcessMonitor &monitor = GetMonitor();
// Account for the fact that 32-bit targets on powerpc64 really use 64-bit
// registers in ptrace, but expose here 32-bit registers with a higher
// offset.
uint64_t offset = GetRegisterOffset(reg_to_write);
offset &= ~(sizeof(uintptr_t) - 1);
return monitor.WriteRegisterValue(
m_thread.GetID(), offset, GetRegisterName(reg_to_write), value_to_write);
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(
const RegisterInfo *reg_info, RegisterValue &value) {
if (!reg_info)
return false;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsFPR(reg)) {
if (!ReadFPR())
return false;
uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset;
value.SetUInt64(*(uint64_t *)src);
} else if (IsGPR(reg)) {
bool success = ReadRegister(reg, value);
if (success) {
// If our return byte size was greater than the return value reg size,
// then use the type specified by reg_info rather than the uint64_t
// default
if (value.GetByteSize() > reg_info->byte_size)
value.SetType(reg_info);
}
return success;
}
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(
const RegisterInfo *reg_info, const RegisterValue &value) {
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
if (IsGPR(reg)) {
return WriteRegister(reg, value);
} else if (IsFPR(reg)) {
assert(reg_info->byte_offset < sizeof(m_fpr_powerpc));
uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset;
*(uint64_t *)dst = value.GetAsUInt64();
return WriteFPR();
}
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(
DataBufferSP &data_sp) {
bool success = false;
data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
if (ReadGPR() && ReadFPR()) {
uint8_t *dst = data_sp->GetBytes();
success = dst != 0;
if (success) {
::memcpy(dst, &m_gpr_powerpc, GetGPRSize());
dst += GetGPRSize();
}
}
return success;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(
const DataBufferSP &data_sp) {
bool success = false;
if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
uint8_t *src = data_sp->GetBytes();
if (src) {
::memcpy(&m_gpr_powerpc, src, GetGPRSize());
if (WriteGPR()) {
src += GetGPRSize();
::memcpy(&m_fpr_powerpc, src, sizeof(m_fpr_powerpc));
success = WriteFPR();
}
}
}
return success;
}
uint32_t RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(
addr_t addr, size_t size, bool read, bool write) {
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
uint32_t hw_index;
for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index) {
if (IsWatchpointVacant(hw_index))
return SetHardwareWatchpointWithIndex(addr, size, read, write, hw_index);
}
return LLDB_INVALID_INDEX32;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(
bool enable) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint() {
lldb::addr_t pc;
if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
return false;
return true;
}
unsigned RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(
unsigned offset) {
unsigned reg;
for (reg = 0; reg < k_num_registers_powerpc; reg++) {
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
assert(reg < k_num_registers_powerpc && "Invalid register offset.");
return reg;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits() {
return false;
}
addr_t RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(
uint32_t hw_index) {
return LLDB_INVALID_ADDRESS;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(
uint32_t hw_index) {
return false;
}
bool RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(
addr_t addr, size_t size, bool read, bool write, uint32_t hw_index) {
return false;
}
uint32_t
RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints() {
return 0;
}

View File

@ -1,84 +0,0 @@
//===-- RegisterContextPOSIXProcessMonitor_powerpc.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
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_
#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_
#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
#include "RegisterContextPOSIX.h"
class RegisterContextPOSIXProcessMonitor_powerpc
: public RegisterContextPOSIX_powerpc,
public POSIXBreakpointProtocol {
public:
RegisterContextPOSIXProcessMonitor_powerpc(
lldb_private::Thread &thread, uint32_t concrete_frame_idx,
lldb_private::RegisterInfoInterface *register_info);
protected:
bool IsVMX();
bool ReadGPR() override;
bool ReadFPR() override;
bool ReadVMX() override;
bool WriteGPR() override;
bool WriteFPR() override;
bool WriteVMX() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
bool WriteRegister(const unsigned reg,
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
const lldb_private::RegisterValue &value) override;
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
bool write) override;
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
bool UpdateAfterBreakpoint() override;
unsigned GetRegisterIndexFromOffset(unsigned offset) override;
bool IsWatchpointHit(uint32_t hw_index) override;
bool ClearWatchpointHits() override;
lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
bool write, uint32_t hw_index) override;
uint32_t NumSupportedHardwareWatchpoints() override;
private:
ProcessMonitor &GetMonitor();
};
#endif

Some files were not shown because too many files have changed in this diff Show More