-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb] Add constant value mode for RegisterLocation in UnwindPlans #100624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb] Add constant value mode for RegisterLocation in UnwindPlans #100624
Conversation
This is useful for language runtimes that compute register values by inspecting the state of the currently running process. Currently, there are no mechanisms enabling these runtimes to set register values to arbitrary values. The alternative considered would involve creating a dwarf expression that produces an arbitrary integer (e.g. using OP_constu). However, the current data structure for Rows is such that they do not own any memory associated with dwarf expressions, which implies any such expression would need to have static storage and therefore could not contain a runtime value. Adding a new rule for constants leads to a simpler implementation. It's also worth noting that this does not make the "Location" union any bigger, since it already contains a pointer+size pair.
@llvm/pr-subscribers-lldb Author: Felipe de Azevedo Piovezan (felipepiovezan) ChangesThis is useful for language runtimes that compute register values by inspecting the state of the currently running process. Currently, there are no mechanisms enabling these runtimes to set register values to arbitrary values. The alternative considered would involve creating a dwarf expression that produces an arbitrary integer (e.g. using OP_constu). However, the current data structure for Rows is such that they do not own any memory associated with dwarf expressions, which implies any such expression would need to have static storage and therefore could not contain a runtime value. Adding a new rule for constants leads to a simpler implementation. It's also worth noting that this does not make the "Location" union any bigger, since it already contains a pointer+size pair. Full diff: https://github.com/llvm/llvm-project/pull/100624.diff 3 Files Affected:
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index ebb0ec421da72..a9e8406608ff3 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -68,7 +68,8 @@ class UnwindPlan {
isAFAPlusOffset, // reg = AFA + offset
inOtherRegister, // reg = other reg
atDWARFExpression, // reg = deref(eval(dwarf_expr))
- isDWARFExpression // reg = eval(dwarf_expr)
+ isDWARFExpression, // reg = eval(dwarf_expr)
+ isConstant // reg = constant
};
RegisterLocation() : m_location() {}
@@ -105,6 +106,15 @@ class UnwindPlan {
bool IsDWARFExpression() const { return m_type == isDWARFExpression; }
+ bool IsConstant() const { return m_type == isConstant; }
+
+ void SetIsConstant(uint64_t value) {
+ m_type = isConstant;
+ m_location.constant_value = value;
+ }
+
+ uint64_t GetConstant() const { return m_location.constant_value; }
+
void SetAtCFAPlusOffset(int32_t offset) {
m_type = atCFAPlusOffset;
m_location.offset = offset;
@@ -192,6 +202,8 @@ class UnwindPlan {
const uint8_t *opcodes;
uint16_t length;
} expr;
+ // For m_type == isConstant
+ uint64_t constant_value;
} m_location;
};
@@ -358,6 +370,9 @@ class UnwindPlan {
bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace);
+ bool SetRegisterLocationToIsConstant(uint32_t reg_num, uint64_t constant,
+ bool can_replace);
+
// When this UnspecifiedRegistersAreUndefined mode is
// set, any register that is not specified by this Row will
// be described as Undefined.
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
index e258a4e3d82f2..fcd3154a01d82 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -46,6 +46,8 @@ operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
return !memcmp(m_location.expr.opcodes, rhs.m_location.expr.opcodes,
m_location.expr.length);
break;
+ case isConstant:
+ return m_location.constant_value == rhs.m_location.constant_value;
}
}
return false;
@@ -153,6 +155,9 @@ void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
if (m_type == atDWARFExpression)
s.PutChar(']');
} break;
+ case isConstant:
+ s.Printf("=%x", m_location.offset);
+ break;
}
}
@@ -351,6 +356,18 @@ bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num,
return true;
}
+bool UnwindPlan::Row::SetRegisterLocationToIsConstant(uint32_t reg_num,
+ uint64_t constant,
+ bool can_replace) {
+ if (!can_replace &&
+ m_register_locations.find(reg_num) != m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetIsConstant(constant);
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
m_afa_value == rhs.m_afa_value &&
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index 95e8abd763d53..f74f1dc0e1b80 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -1694,6 +1694,15 @@ RegisterContextUnwind::SavedLocationForRegister(
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
}
+ if (unwindplan_regloc.IsConstant()) {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = unwindplan_regloc.GetConstant();
+ m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg("supplying caller's register %s (%d) via constant value",
+ regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
UnwindLogMsg("no save location for %s (%d) in this stack frame",
regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB));
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. One small nit on the Dump method.
As a bit of background, this would be very unusual for a normal UnwindPlan that is reused for a function in many different contexts (different places on the stack during the program runtime). Felipe is dealing with the special case when the Swift LanguageRuntime creates an UnwindPlan that is used once in a given stack, and not saved in the UnwindTable for this Module. Felipe could have constructed a DWARF expression, where the register value was stored in memory, or a DWARF expression with a constant value, but then we'd need to add a DataBufferSP
to the RegisterLocation
to have ownership of this heap-allocated dwarf expression, in addition to hand-creating the DWARF expression bytecodes. It was a lot more straightforward to add this type of "this register is value x" for this one-shot UnwindPlan's that a LanguageRuntime can provide.
lldb/source/Symbol/UnwindPlan.cpp
Outdated
@@ -153,6 +155,9 @@ void UnwindPlan::Row::RegisterLocation::Dump(Stream &s, | |||
if (m_type == atDWARFExpression) | |||
s.PutChar(']'); | |||
} break; | |||
case isConstant: | |||
s.Printf("=%x", m_location.offset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the Printf be ("=0x%" PRIx64, m_location.constant_value)
? If you do an unwind with one of these register locations in use, we should see this output when the unwind engine shows the unwind rules being used for this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohh oops, you're totally right! Fixed!
This is useful for language runtimes that compute register values by inspecting the state of the currently running process. Currently, there are no mechanisms enabling these runtimes to set register values to arbitrary values.
The alternative considered would involve creating a dwarf expression that produces an arbitrary integer (e.g. using OP_constu). However, the current data structure for Rows is such that they do not own any memory associated with dwarf expressions, which implies any such expression would need to have static storage and therefore could not contain a runtime value.
Adding a new rule for constants leads to a simpler implementation. It's also worth noting that this does not make the "Location" union any bigger, since it already contains a pointer+size pair.