|
4 | 4 | package python // import "go.opentelemetry.io/ebpf-profiler/interpreter/python" |
5 | 5 |
|
6 | 6 | import ( |
| 7 | + "fmt" |
| 8 | + |
7 | 9 | ah "go.opentelemetry.io/ebpf-profiler/armhelpers" |
8 | 10 | "go.opentelemetry.io/ebpf-profiler/libpf" |
| 11 | + "go.opentelemetry.io/ebpf-profiler/libpf/pfelf" |
9 | 12 | aa "golang.org/x/arch/arm64/arm64asm" |
10 | 13 | ) |
11 | 14 |
|
@@ -100,3 +103,98 @@ func decodeStubArgumentARM64(code []byte, |
100 | 103 |
|
101 | 104 | return libpf.SymbolValueInvalid |
102 | 105 | } |
| 106 | + |
| 107 | +// extractTLSOffsetFromCodeARM64 extracts the TLS offset by analyzing ARM64 assembly code. |
| 108 | +// It looks for the pattern: MRS Xn, TPIDR_EL0 followed by ADD Xn, Xn, #offset or LDR [Xn, #offset]. |
| 109 | +func extractTLSOffsetFromCodeARM64(code []byte, baseAddr uint64, visited map[uint64]bool, depth int, ef *pfelf.File) (int64, error) { |
| 110 | + // Prevent infinite recursion |
| 111 | + const maxDepth = 5 |
| 112 | + if depth > maxDepth { |
| 113 | + return 0, fmt.Errorf("max recursion depth exceeded") |
| 114 | + } |
| 115 | + |
| 116 | + if visited[baseAddr] { |
| 117 | + return 0, fmt.Errorf("already visited address 0x%x", baseAddr) |
| 118 | + } |
| 119 | + visited[baseAddr] = true |
| 120 | + |
| 121 | + foundMRS := false |
| 122 | + var tpReg int |
| 123 | + |
| 124 | + for offs := 0; offs < len(code)-4; offs += 4 { |
| 125 | + inst, err := aa.Decode(code[offs:]) |
| 126 | + if err != nil { |
| 127 | + continue |
| 128 | + } |
| 129 | + |
| 130 | + // Check for MRS Xn, TPIDR_EL0 (system register S3_3_C13_C0_2) |
| 131 | + if inst.Op == aa.MRS && inst.Args[1].String() == "S3_3_C13_C0_2" { |
| 132 | + reg, ok := ah.Xreg2num(inst.Args[0]) |
| 133 | + if !ok { |
| 134 | + continue |
| 135 | + } |
| 136 | + tpReg = reg |
| 137 | + foundMRS = true |
| 138 | + |
| 139 | + // Look ahead for ADD or LDR using this register |
| 140 | + for j := offs + 4; j < len(code)-4 && j < offs+64; j += 4 { |
| 141 | + nextInst, err := aa.Decode(code[j:]) |
| 142 | + if err != nil { |
| 143 | + continue |
| 144 | + } |
| 145 | + |
| 146 | + // Check for ADD Xd, Xn, #imm |
| 147 | + if nextInst.Op == aa.ADD { |
| 148 | + destReg, destOk := ah.Xreg2num(nextInst.Args[0]) |
| 149 | + srcReg, srcOk := ah.Xreg2num(nextInst.Args[1]) |
| 150 | + imm, immOk := ah.DecodeImmediate(nextInst.Args[2]) |
| 151 | + |
| 152 | + if destOk && srcOk && immOk && srcReg == tpReg { |
| 153 | + if imm > 0 && imm < 0x1000 { |
| 154 | + return int64(imm), nil |
| 155 | + } |
| 156 | + // Track the new register holding TP+offset |
| 157 | + tpReg = destReg |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + // Check for LDR Xm, [Xn, #imm] |
| 162 | + if nextInst.Op == aa.LDR { |
| 163 | + // Args[1] is MemImmediate |
| 164 | + if mem, ok := nextInst.Args[1].(aa.MemImmediate); ok { |
| 165 | + baseReg, regOk := ah.Xreg2num(mem.Base) |
| 166 | + imm, immOk := ah.DecodeImmediate(mem) |
| 167 | + |
| 168 | + if regOk && immOk && baseReg == tpReg { |
| 169 | + if imm > 0 && imm < 0x1000 { |
| 170 | + return int64(imm), nil |
| 171 | + } |
| 172 | + } |
| 173 | + } |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + // Check for unconditional branch |
| 179 | + if inst.Op == aa.B { |
| 180 | + if pcrel, ok := inst.Args[0].(aa.PCRel); ok { |
| 181 | + targetAddr := int64(baseAddr) + int64(offs) + int64(pcrel) |
| 182 | + |
| 183 | + if targetAddr > 0 && targetAddr < 0x100000000 && !visited[uint64(targetAddr)] { |
| 184 | + targetCode := make([]byte, 256) |
| 185 | + err := ef.GetRemoteMemory().Read(libpf.Address(targetAddr), targetCode) |
| 186 | + if err == nil { |
| 187 | + if result, err := extractTLSOffsetFromCodeARM64(targetCode, uint64(targetAddr), visited, depth+1, ef); err == nil { |
| 188 | + return result, nil |
| 189 | + } |
| 190 | + } |
| 191 | + } |
| 192 | + } |
| 193 | + } |
| 194 | + } |
| 195 | + |
| 196 | + if !foundMRS { |
| 197 | + return 0, fmt.Errorf("could not find MRS TPIDR_EL0 instruction") |
| 198 | + } |
| 199 | + return 0, fmt.Errorf("found MRS TPIDR_EL0 but no matching ADD/LDR with TLS offset") |
| 200 | +} |
0 commit comments