mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-19 02:29:40 +00:00
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:
commit
d409305fa3
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>,
|
||||
|
@ -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(); }
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -82,6 +82,7 @@ static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
|
||||
case CodeGenOptions::ProfileCSIRInstr:
|
||||
return "csllvm";
|
||||
}
|
||||
llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
|
||||
}
|
||||
|
||||
llvm::Optional<bool>
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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())
|
||||
|
@ -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()) {
|
||||
|
@ -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";
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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?
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) + "'";
|
||||
|
@ -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
|
||||
------------------------
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
@ -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_
|
@ -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 ®ctx = 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();
|
||||
}
|
@ -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;
|
@ -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"
|
||||
|
@ -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 ®_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 ®_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__)
|
@ -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 ®_value) override;
|
||||
|
||||
Status WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_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__)
|
@ -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 ®_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 ®_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__)
|
@ -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 ®_value) override;
|
||||
|
||||
Status WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_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__)
|
@ -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 ®_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 ®_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__)
|
@ -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 ®_value) override;
|
||||
|
||||
Status WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_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__)
|
@ -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 ®_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 ®_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__)
|
@ -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 ®_value) override;
|
||||
|
||||
Status WriteRegister(const RegisterInfo *reg_info,
|
||||
const RegisterValue ®_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__)
|
@ -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);
|
@ -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;
|
@ -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>
|
@ -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; }
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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_
|
File diff suppressed because it is too large
Load Diff
@ -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_
|
@ -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_
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user