Skip to content

Commit

Permalink
arm64/DWARF: Add check for Arm64 DWARF Expressions
Browse files Browse the repository at this point in the history
DWARF Expressions are encoded with a `DW_CFA_def_cfa_expression` or
`DW_CFA_expression` (as per aarch64 DWARF ABI). However
grepping for either in `.eh_frame` debug information did not show any
results (including hardcoded PLT patter heuristics) unlike in x86.
(See #1058 for the x86 implementation).

Tested on system binaries and libc in multiple distros:
Debian, Fedora, Centos, Ubuntu

Workflow:
```
`docker run -it --network=host arm64v8/fedora bash`
`docker cp 0693985d3bba:/ ./fedrepo`

`sudo readelf -wf ./fedrepo/bin/* 2>/dev/null | grep
DW_CFA_cfa_def_expression`
`sudo readelf -wF ./centos-repo/bin/* 2>/dev/null | grep exp`

```
Return an error for now if we come across an expression in Arm64 binaries.

Signed-off-by: Sumera Priyadarsini <[email protected]>
  • Loading branch information
Sylfrena committed Jan 26, 2024
1 parent a585863 commit 764a0de
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 16 deletions.
53 changes: 37 additions & 16 deletions pkg/stack/unwind/dwarf_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const (
ExpressionUnknown DWARFExpressionID = iota
ExpressionPlt1
ExpressionPlt2
ExpressionArm1
ExpressionArm2
)

// DWARF expressions that we recognize.
Expand Down Expand Up @@ -71,25 +73,44 @@ func equalBytes(a, b []byte) bool {
return true
}

// expressionIdentifierX86 returns identifier for x86 DWARF Expressions
func expressionIdentifierX86(cleanedExpression []byte) DWARFExpressionID {
if equalBytes(Plt1[:], cleanedExpression) {
return ExpressionPlt1
}
if equalBytes(Plt2[:], cleanedExpression) {
return ExpressionPlt2
}
return ExpressionUnknown
}

// expressionIdentifierArm64 returns identifier for Arm64 expressions
func expressionIdentifierArm64(cleanedExpression []byte) DWARFExpressionID {
if equalBytes([]byte{frame.DW_CFA_def_cfa_expression}, cleanedExpression) {
return ExpressionArm1
}
if equalBytes([]byte{frame.DW_CFA_expression}, cleanedExpression) {
return ExpressionArm2
}
return ExpressionUnknown
}

// ExpressionIdentifier returns the identifier for recognized
// DWARF expressions.
func ExpressionIdentifier(expression []byte, arch elf.Machine) DWARFExpressionID {
if arch == elf.EM_X86_64 {
cleanedExpression := make([]byte, 0, len(expression))
for _, opcode := range expression {
if opcode == 0x0 {
continue
}
cleanedExpression = append(cleanedExpression, opcode)
}

if equalBytes(Plt1[:], cleanedExpression) {
return ExpressionPlt1
}

if equalBytes(Plt2[:], cleanedExpression) {
return ExpressionPlt2
cleanedExpression := make([]byte, 0, len(expression))
for _, opcode := range expression {
if opcode == 0x0 {
continue
}
cleanedExpression = append(cleanedExpression, opcode)
}
return ExpressionUnknown
var expressionID DWARFExpressionID
if arch == elf.EM_X86_64 {
expressionID = expressionIdentifierX86(cleanedExpression)
}
if arch == elf.EM_AARCH64 {
expressionID = expressionIdentifierArm64(cleanedExpression)
}
return expressionID
}
3 changes: 3 additions & 0 deletions pkg/stack/unwind/unwind_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ func (ptb *UnwindTableBuilder) PrintTable(writer io.Writer, path string, compact
fmt.Fprintf(writer, "\tLoc: %x CFA: $%s=%-4d", unwindRow.Loc, CFAReg, unwindRow.CFA.Offset)
case frame.RuleExpression:
expressionID := ExpressionIdentifier(unwindRow.CFA.Expression, arch)
if expressionID == ExpressionArm1 || expressionID == ExpressionArm2 {
return fmt.Errorf("CFA rule at Loc: %x CFA: exp %d has not been implemented and is unexpected for Arm64", unwindRow.Loc, expressionID)
}
if expressionID == ExpressionUnknown {
fmt.Fprintf(writer, "\tLoc: %x CFA: exp ", unwindRow.Loc)
} else {
Expand Down

0 comments on commit 764a0de

Please sign in to comment.