1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/profiler/chrome_unwinder_android.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/memory/aligned_memory.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/numerics/checked_math.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/profiler/chrome_unwind_info_android.h"
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker namespace {
17*6777b538SAndroid Build Coastguard Worker
GetRegisterPointer(RegisterContext * context,uint8_t register_index)18*6777b538SAndroid Build Coastguard Worker uintptr_t* GetRegisterPointer(RegisterContext* context,
19*6777b538SAndroid Build Coastguard Worker uint8_t register_index) {
20*6777b538SAndroid Build Coastguard Worker DCHECK_LE(register_index, 15);
21*6777b538SAndroid Build Coastguard Worker static unsigned long RegisterContext::*const registers[16] = {
22*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r0, &RegisterContext::arm_r1,
23*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r2, &RegisterContext::arm_r3,
24*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r4, &RegisterContext::arm_r5,
25*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r6, &RegisterContext::arm_r7,
26*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r8, &RegisterContext::arm_r9,
27*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_r10, &RegisterContext::arm_fp,
28*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_ip, &RegisterContext::arm_sp,
29*6777b538SAndroid Build Coastguard Worker &RegisterContext::arm_lr, &RegisterContext::arm_pc,
30*6777b538SAndroid Build Coastguard Worker };
31*6777b538SAndroid Build Coastguard Worker return reinterpret_cast<uintptr_t*>(&(context->*registers[register_index]));
32*6777b538SAndroid Build Coastguard Worker }
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker // Pops the value on the top of stack out and assign it to target register.
35*6777b538SAndroid Build Coastguard Worker // This is equivalent to arm instruction `Pop r[n]` where n = `register_index`.
36*6777b538SAndroid Build Coastguard Worker // Returns whether the pop is successful.
PopRegister(RegisterContext * context,uint8_t register_index)37*6777b538SAndroid Build Coastguard Worker bool PopRegister(RegisterContext* context, uint8_t register_index) {
38*6777b538SAndroid Build Coastguard Worker const uintptr_t sp = RegisterContextStackPointer(context);
39*6777b538SAndroid Build Coastguard Worker const uintptr_t stacktop_value = *reinterpret_cast<uintptr_t*>(sp);
40*6777b538SAndroid Build Coastguard Worker const auto new_sp = CheckedNumeric<uintptr_t>(sp) + sizeof(uintptr_t);
41*6777b538SAndroid Build Coastguard Worker const bool success =
42*6777b538SAndroid Build Coastguard Worker new_sp.AssignIfValid(&RegisterContextStackPointer(context));
43*6777b538SAndroid Build Coastguard Worker if (success)
44*6777b538SAndroid Build Coastguard Worker *GetRegisterPointer(context, register_index) = stacktop_value;
45*6777b538SAndroid Build Coastguard Worker return success;
46*6777b538SAndroid Build Coastguard Worker }
47*6777b538SAndroid Build Coastguard Worker
48*6777b538SAndroid Build Coastguard Worker // Decodes the given bytes as an ULEB128 format number and advances the bytes
49*6777b538SAndroid Build Coastguard Worker // pointer by the size of ULEB128.
50*6777b538SAndroid Build Coastguard Worker //
51*6777b538SAndroid Build Coastguard Worker // This function assumes the given bytes are in valid ULEB128
52*6777b538SAndroid Build Coastguard Worker // format and the decoded number should not overflow `uintptr_t` type.
DecodeULEB128(const uint8_t * & bytes)53*6777b538SAndroid Build Coastguard Worker uintptr_t DecodeULEB128(const uint8_t*& bytes) {
54*6777b538SAndroid Build Coastguard Worker uintptr_t value = 0;
55*6777b538SAndroid Build Coastguard Worker unsigned shift = 0;
56*6777b538SAndroid Build Coastguard Worker do {
57*6777b538SAndroid Build Coastguard Worker DCHECK_LE(shift, sizeof(uintptr_t) * 8); // ULEB128 must not overflow.
58*6777b538SAndroid Build Coastguard Worker value += (*bytes & 0x7fu) << shift;
59*6777b538SAndroid Build Coastguard Worker shift += 7;
60*6777b538SAndroid Build Coastguard Worker } while (*bytes++ & 0x80);
61*6777b538SAndroid Build Coastguard Worker return value;
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker
GetTopBits(uint8_t byte,unsigned bits)64*6777b538SAndroid Build Coastguard Worker uint8_t GetTopBits(uint8_t byte, unsigned bits) {
65*6777b538SAndroid Build Coastguard Worker DCHECK_LE(bits, 8u);
66*6777b538SAndroid Build Coastguard Worker return byte >> (8 - bits);
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker
69*6777b538SAndroid Build Coastguard Worker } // namespace
70*6777b538SAndroid Build Coastguard Worker
ChromeUnwinderAndroid(const ChromeUnwindInfoAndroid & unwind_info,uintptr_t chrome_module_base_address,uintptr_t text_section_start_address)71*6777b538SAndroid Build Coastguard Worker ChromeUnwinderAndroid::ChromeUnwinderAndroid(
72*6777b538SAndroid Build Coastguard Worker const ChromeUnwindInfoAndroid& unwind_info,
73*6777b538SAndroid Build Coastguard Worker uintptr_t chrome_module_base_address,
74*6777b538SAndroid Build Coastguard Worker uintptr_t text_section_start_address)
75*6777b538SAndroid Build Coastguard Worker : unwind_info_(unwind_info),
76*6777b538SAndroid Build Coastguard Worker chrome_module_base_address_(chrome_module_base_address),
77*6777b538SAndroid Build Coastguard Worker text_section_start_address_(text_section_start_address) {
78*6777b538SAndroid Build Coastguard Worker DCHECK_GT(text_section_start_address_, chrome_module_base_address_);
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker
CanUnwindFrom(const Frame & current_frame) const81*6777b538SAndroid Build Coastguard Worker bool ChromeUnwinderAndroid::CanUnwindFrom(const Frame& current_frame) const {
82*6777b538SAndroid Build Coastguard Worker return current_frame.module &&
83*6777b538SAndroid Build Coastguard Worker current_frame.module->GetBaseAddress() == chrome_module_base_address_;
84*6777b538SAndroid Build Coastguard Worker }
85*6777b538SAndroid Build Coastguard Worker
TryUnwind(RegisterContext * thread_context,uintptr_t stack_top,std::vector<Frame> * stack)86*6777b538SAndroid Build Coastguard Worker UnwindResult ChromeUnwinderAndroid::TryUnwind(RegisterContext* thread_context,
87*6777b538SAndroid Build Coastguard Worker uintptr_t stack_top,
88*6777b538SAndroid Build Coastguard Worker std::vector<Frame>* stack) {
89*6777b538SAndroid Build Coastguard Worker DCHECK(CanUnwindFrom(stack->back()));
90*6777b538SAndroid Build Coastguard Worker uintptr_t frame_initial_sp = RegisterContextStackPointer(thread_context);
91*6777b538SAndroid Build Coastguard Worker const uintptr_t unwind_initial_pc =
92*6777b538SAndroid Build Coastguard Worker RegisterContextInstructionPointer(thread_context);
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker do {
95*6777b538SAndroid Build Coastguard Worker const uintptr_t pc = RegisterContextInstructionPointer(thread_context);
96*6777b538SAndroid Build Coastguard Worker const uintptr_t instruction_byte_offset_from_text_section_start =
97*6777b538SAndroid Build Coastguard Worker pc - text_section_start_address_;
98*6777b538SAndroid Build Coastguard Worker
99*6777b538SAndroid Build Coastguard Worker const std::optional<FunctionOffsetTableIndex> function_offset_table_index =
100*6777b538SAndroid Build Coastguard Worker GetFunctionTableIndexFromInstructionOffset(
101*6777b538SAndroid Build Coastguard Worker unwind_info_.page_table, unwind_info_.function_table,
102*6777b538SAndroid Build Coastguard Worker instruction_byte_offset_from_text_section_start);
103*6777b538SAndroid Build Coastguard Worker
104*6777b538SAndroid Build Coastguard Worker if (!function_offset_table_index) {
105*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker const uint32_t current_unwind_instruction_index =
109*6777b538SAndroid Build Coastguard Worker GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(
110*6777b538SAndroid Build Coastguard Worker &unwind_info_
111*6777b538SAndroid Build Coastguard Worker .function_offset_table[function_offset_table_index
112*6777b538SAndroid Build Coastguard Worker ->function_offset_table_byte_index],
113*6777b538SAndroid Build Coastguard Worker function_offset_table_index
114*6777b538SAndroid Build Coastguard Worker ->instruction_offset_from_function_start);
115*6777b538SAndroid Build Coastguard Worker
116*6777b538SAndroid Build Coastguard Worker const uint8_t* current_unwind_instruction =
117*6777b538SAndroid Build Coastguard Worker &unwind_info_
118*6777b538SAndroid Build Coastguard Worker .unwind_instruction_table[current_unwind_instruction_index];
119*6777b538SAndroid Build Coastguard Worker
120*6777b538SAndroid Build Coastguard Worker UnwindInstructionResult instruction_result;
121*6777b538SAndroid Build Coastguard Worker bool pc_was_updated = false;
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker do {
124*6777b538SAndroid Build Coastguard Worker instruction_result = ExecuteUnwindInstruction(
125*6777b538SAndroid Build Coastguard Worker current_unwind_instruction, pc_was_updated, thread_context);
126*6777b538SAndroid Build Coastguard Worker const uintptr_t sp = RegisterContextStackPointer(thread_context);
127*6777b538SAndroid Build Coastguard Worker if (sp > stack_top || sp < frame_initial_sp ||
128*6777b538SAndroid Build Coastguard Worker !IsAligned(sp, sizeof(uintptr_t))) {
129*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
130*6777b538SAndroid Build Coastguard Worker }
131*6777b538SAndroid Build Coastguard Worker } while (instruction_result ==
132*6777b538SAndroid Build Coastguard Worker UnwindInstructionResult::kInstructionPending);
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard Worker if (instruction_result == UnwindInstructionResult::kAborted) {
135*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(instruction_result, UnwindInstructionResult::kCompleted);
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker const uintptr_t new_sp = RegisterContextStackPointer(thread_context);
141*6777b538SAndroid Build Coastguard Worker // Validate SP is properly aligned across frames.
142*6777b538SAndroid Build Coastguard Worker // See
143*6777b538SAndroid Build Coastguard Worker // https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/using-the-stack-in-aarch32-and-aarch64
144*6777b538SAndroid Build Coastguard Worker // for SP alignment rules.
145*6777b538SAndroid Build Coastguard Worker if (!IsAligned(new_sp, 2 * sizeof(uintptr_t))) {
146*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker // Validate that SP does not decrease across frames.
149*6777b538SAndroid Build Coastguard Worker const bool is_leaf_frame = stack->size() == 1;
150*6777b538SAndroid Build Coastguard Worker // Each frame unwind is expected to only pop from stack memory, which will
151*6777b538SAndroid Build Coastguard Worker // cause sp to increase.
152*6777b538SAndroid Build Coastguard Worker // Non-Leaf frames are expected to at least pop lr off stack, so sp is
153*6777b538SAndroid Build Coastguard Worker // expected to strictly increase for non-leaf frames.
154*6777b538SAndroid Build Coastguard Worker if (new_sp <= (is_leaf_frame ? frame_initial_sp - 1 : frame_initial_sp)) {
155*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker
158*6777b538SAndroid Build Coastguard Worker // For leaf functions, if SP does not change, PC must change, otherwise,
159*6777b538SAndroid Build Coastguard Worker // the overall execution state will be the same before/after the frame
160*6777b538SAndroid Build Coastguard Worker // unwind.
161*6777b538SAndroid Build Coastguard Worker if (is_leaf_frame && new_sp == frame_initial_sp &&
162*6777b538SAndroid Build Coastguard Worker RegisterContextInstructionPointer(thread_context) ==
163*6777b538SAndroid Build Coastguard Worker unwind_initial_pc) {
164*6777b538SAndroid Build Coastguard Worker return UnwindResult::kAborted;
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker frame_initial_sp = new_sp;
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker stack->emplace_back(RegisterContextInstructionPointer(thread_context),
170*6777b538SAndroid Build Coastguard Worker module_cache()->GetModuleForAddress(
171*6777b538SAndroid Build Coastguard Worker RegisterContextInstructionPointer(thread_context)));
172*6777b538SAndroid Build Coastguard Worker } while (CanUnwindFrom(stack->back()));
173*6777b538SAndroid Build Coastguard Worker return UnwindResult::kUnrecognizedFrame;
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker
ExecuteUnwindInstruction(const uint8_t * & instruction,bool & pc_was_updated,RegisterContext * thread_context)176*6777b538SAndroid Build Coastguard Worker UnwindInstructionResult ExecuteUnwindInstruction(
177*6777b538SAndroid Build Coastguard Worker const uint8_t*& instruction,
178*6777b538SAndroid Build Coastguard Worker bool& pc_was_updated,
179*6777b538SAndroid Build Coastguard Worker RegisterContext* thread_context) {
180*6777b538SAndroid Build Coastguard Worker if (GetTopBits(*instruction, 2) == 0b00) {
181*6777b538SAndroid Build Coastguard Worker // 00xxxxxx
182*6777b538SAndroid Build Coastguard Worker // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive.
183*6777b538SAndroid Build Coastguard Worker const uintptr_t offset = ((*instruction++ & 0b00111111u) << 2) + 4;
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Worker const auto new_sp =
186*6777b538SAndroid Build Coastguard Worker CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) +
187*6777b538SAndroid Build Coastguard Worker offset;
188*6777b538SAndroid Build Coastguard Worker if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
189*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
190*6777b538SAndroid Build Coastguard Worker }
191*6777b538SAndroid Build Coastguard Worker } else if (GetTopBits(*instruction, 2) == 0b01) {
192*6777b538SAndroid Build Coastguard Worker // 01xxxxxx
193*6777b538SAndroid Build Coastguard Worker // vsp = vsp - (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive.
194*6777b538SAndroid Build Coastguard Worker const uintptr_t offset = ((*instruction++ & 0b00111111u) << 2) + 4;
195*6777b538SAndroid Build Coastguard Worker const auto new_sp =
196*6777b538SAndroid Build Coastguard Worker CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) -
197*6777b538SAndroid Build Coastguard Worker offset;
198*6777b538SAndroid Build Coastguard Worker if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
199*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker } else if (GetTopBits(*instruction, 4) == 0b1001) {
202*6777b538SAndroid Build Coastguard Worker // 1001nnnn (nnnn != 13,15)
203*6777b538SAndroid Build Coastguard Worker // Set vsp = r[nnnn].
204*6777b538SAndroid Build Coastguard Worker const uint8_t register_index = *instruction++ & 0b00001111;
205*6777b538SAndroid Build Coastguard Worker DCHECK_NE(register_index, 13); // Must not set sp to sp.
206*6777b538SAndroid Build Coastguard Worker DCHECK_NE(register_index, 15); // Must not set sp to pc.
207*6777b538SAndroid Build Coastguard Worker // Note: We shouldn't have cases that are setting caller-saved registers
208*6777b538SAndroid Build Coastguard Worker // using this instruction.
209*6777b538SAndroid Build Coastguard Worker DCHECK_GE(register_index, 4);
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker RegisterContextStackPointer(thread_context) =
212*6777b538SAndroid Build Coastguard Worker *GetRegisterPointer(thread_context, register_index);
213*6777b538SAndroid Build Coastguard Worker } else if (GetTopBits(*instruction, 5) == 0b10101) {
214*6777b538SAndroid Build Coastguard Worker // 10101nnn
215*6777b538SAndroid Build Coastguard Worker // Pop r4-r[4+nnn], r14
216*6777b538SAndroid Build Coastguard Worker const uint8_t max_register_index = (*instruction++ & 0b00000111u) + 4;
217*6777b538SAndroid Build Coastguard Worker for (uint8_t n = 4; n <= max_register_index; n++) {
218*6777b538SAndroid Build Coastguard Worker if (!PopRegister(thread_context, n)) {
219*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
220*6777b538SAndroid Build Coastguard Worker }
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker if (!PopRegister(thread_context, 14)) {
223*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
224*6777b538SAndroid Build Coastguard Worker }
225*6777b538SAndroid Build Coastguard Worker } else if (*instruction == 0b10000000 && *(instruction + 1) == 0) {
226*6777b538SAndroid Build Coastguard Worker // 10000000 00000000
227*6777b538SAndroid Build Coastguard Worker // Refuse to unwind.
228*6777b538SAndroid Build Coastguard Worker instruction += 2;
229*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
230*6777b538SAndroid Build Coastguard Worker } else if (GetTopBits(*instruction, 4) == 0b1000) {
231*6777b538SAndroid Build Coastguard Worker const uint32_t register_bitmask =
232*6777b538SAndroid Build Coastguard Worker ((*instruction & 0xfu) << 8) + *(instruction + 1);
233*6777b538SAndroid Build Coastguard Worker instruction += 2;
234*6777b538SAndroid Build Coastguard Worker // 1000iiii iiiiiiii
235*6777b538SAndroid Build Coastguard Worker // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
236*6777b538SAndroid Build Coastguard Worker for (uint8_t register_index = 4; register_index < 16; register_index++) {
237*6777b538SAndroid Build Coastguard Worker if (register_bitmask & (1 << (register_index - 4))) {
238*6777b538SAndroid Build Coastguard Worker if (!PopRegister(thread_context, register_index)) {
239*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
240*6777b538SAndroid Build Coastguard Worker }
241*6777b538SAndroid Build Coastguard Worker }
242*6777b538SAndroid Build Coastguard Worker }
243*6777b538SAndroid Build Coastguard Worker // If we set pc (r15) with value on stack, we should no longer copy lr to
244*6777b538SAndroid Build Coastguard Worker // pc on COMPLETE.
245*6777b538SAndroid Build Coastguard Worker pc_was_updated |= register_bitmask & (1 << (15 - 4));
246*6777b538SAndroid Build Coastguard Worker } else if (*instruction == 0b10110000) {
247*6777b538SAndroid Build Coastguard Worker // Finish
248*6777b538SAndroid Build Coastguard Worker // Code 0xb0, Finish, copies VRS[r14] to VRS[r15] and also
249*6777b538SAndroid Build Coastguard Worker // indicates that no further instructions are to be processed for this
250*6777b538SAndroid Build Coastguard Worker // frame.
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard Worker instruction++;
253*6777b538SAndroid Build Coastguard Worker // Only copy lr to pc when pc is not updated by other instructions before.
254*6777b538SAndroid Build Coastguard Worker if (!pc_was_updated)
255*6777b538SAndroid Build Coastguard Worker thread_context->arm_pc = thread_context->arm_lr;
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kCompleted;
258*6777b538SAndroid Build Coastguard Worker } else if (*instruction == 0b10110010) {
259*6777b538SAndroid Build Coastguard Worker // 10110010 uleb128
260*6777b538SAndroid Build Coastguard Worker // vsp = vsp + 0x204 + (uleb128 << 2)
261*6777b538SAndroid Build Coastguard Worker // (for vsp increments of 0x104-0x200, use 00xxxxxx twice)
262*6777b538SAndroid Build Coastguard Worker instruction++;
263*6777b538SAndroid Build Coastguard Worker const auto new_sp =
264*6777b538SAndroid Build Coastguard Worker CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) +
265*6777b538SAndroid Build Coastguard Worker (CheckedNumeric<uintptr_t>(DecodeULEB128(instruction)) << 2) + 0x204;
266*6777b538SAndroid Build Coastguard Worker
267*6777b538SAndroid Build Coastguard Worker if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context))) {
268*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kAborted;
269*6777b538SAndroid Build Coastguard Worker }
270*6777b538SAndroid Build Coastguard Worker } else {
271*6777b538SAndroid Build Coastguard Worker NOTREACHED();
272*6777b538SAndroid Build Coastguard Worker }
273*6777b538SAndroid Build Coastguard Worker return UnwindInstructionResult::kInstructionPending;
274*6777b538SAndroid Build Coastguard Worker }
275*6777b538SAndroid Build Coastguard Worker
GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(const uint8_t * function_offset_table_entry,int instruction_offset_from_function_start)276*6777b538SAndroid Build Coastguard Worker uintptr_t GetFirstUnwindInstructionIndexFromFunctionOffsetTableEntry(
277*6777b538SAndroid Build Coastguard Worker const uint8_t* function_offset_table_entry,
278*6777b538SAndroid Build Coastguard Worker int instruction_offset_from_function_start) {
279*6777b538SAndroid Build Coastguard Worker DCHECK_GE(instruction_offset_from_function_start, 0);
280*6777b538SAndroid Build Coastguard Worker const uint8_t* current_function_offset_table_position =
281*6777b538SAndroid Build Coastguard Worker function_offset_table_entry;
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker do {
284*6777b538SAndroid Build Coastguard Worker const uintptr_t function_offset =
285*6777b538SAndroid Build Coastguard Worker DecodeULEB128(current_function_offset_table_position);
286*6777b538SAndroid Build Coastguard Worker
287*6777b538SAndroid Build Coastguard Worker const uintptr_t unwind_table_index =
288*6777b538SAndroid Build Coastguard Worker DecodeULEB128(current_function_offset_table_position);
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker // Each function always ends at 0 offset. It is guaranteed to find an entry
291*6777b538SAndroid Build Coastguard Worker // as long as the function offset table is well-structured.
292*6777b538SAndroid Build Coastguard Worker if (function_offset <=
293*6777b538SAndroid Build Coastguard Worker static_cast<uint32_t>(instruction_offset_from_function_start))
294*6777b538SAndroid Build Coastguard Worker return unwind_table_index;
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker } while (true);
297*6777b538SAndroid Build Coastguard Worker
298*6777b538SAndroid Build Coastguard Worker NOTREACHED();
299*6777b538SAndroid Build Coastguard Worker return 0;
300*6777b538SAndroid Build Coastguard Worker }
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker const std::optional<FunctionOffsetTableIndex>
GetFunctionTableIndexFromInstructionOffset(span<const uint32_t> page_start_instructions,span<const FunctionTableEntry> function_offset_table_indices,uint32_t instruction_byte_offset_from_text_section_start)303*6777b538SAndroid Build Coastguard Worker GetFunctionTableIndexFromInstructionOffset(
304*6777b538SAndroid Build Coastguard Worker span<const uint32_t> page_start_instructions,
305*6777b538SAndroid Build Coastguard Worker span<const FunctionTableEntry> function_offset_table_indices,
306*6777b538SAndroid Build Coastguard Worker uint32_t instruction_byte_offset_from_text_section_start) {
307*6777b538SAndroid Build Coastguard Worker DCHECK(!page_start_instructions.empty());
308*6777b538SAndroid Build Coastguard Worker DCHECK(!function_offset_table_indices.empty());
309*6777b538SAndroid Build Coastguard Worker // First function on first page should always start from 0 offset.
310*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(function_offset_table_indices.front()
311*6777b538SAndroid Build Coastguard Worker .function_start_address_page_instruction_offset,
312*6777b538SAndroid Build Coastguard Worker 0ul);
313*6777b538SAndroid Build Coastguard Worker
314*6777b538SAndroid Build Coastguard Worker const uint16_t page_number =
315*6777b538SAndroid Build Coastguard Worker instruction_byte_offset_from_text_section_start >> 17;
316*6777b538SAndroid Build Coastguard Worker const uint16_t page_instruction_offset =
317*6777b538SAndroid Build Coastguard Worker (instruction_byte_offset_from_text_section_start >> 1) &
318*6777b538SAndroid Build Coastguard Worker 0xffff; // 16 bits.
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker // Invalid instruction_byte_offset_from_text_section_start:
321*6777b538SAndroid Build Coastguard Worker // instruction_byte_offset_from_text_section_start falls after the last page.
322*6777b538SAndroid Build Coastguard Worker if (page_number >= page_start_instructions.size()) {
323*6777b538SAndroid Build Coastguard Worker return std::nullopt;
324*6777b538SAndroid Build Coastguard Worker }
325*6777b538SAndroid Build Coastguard Worker
326*6777b538SAndroid Build Coastguard Worker const span<const FunctionTableEntry>::iterator function_table_entry_start =
327*6777b538SAndroid Build Coastguard Worker function_offset_table_indices.begin() +
328*6777b538SAndroid Build Coastguard Worker checked_cast<ptrdiff_t>(page_start_instructions[page_number]);
329*6777b538SAndroid Build Coastguard Worker const span<const FunctionTableEntry>::iterator function_table_entry_end =
330*6777b538SAndroid Build Coastguard Worker page_number == page_start_instructions.size() - 1
331*6777b538SAndroid Build Coastguard Worker ? function_offset_table_indices.end()
332*6777b538SAndroid Build Coastguard Worker : function_offset_table_indices.begin() +
333*6777b538SAndroid Build Coastguard Worker checked_cast<ptrdiff_t>(
334*6777b538SAndroid Build Coastguard Worker page_start_instructions[page_number + 1]);
335*6777b538SAndroid Build Coastguard Worker
336*6777b538SAndroid Build Coastguard Worker // `std::upper_bound` finds first element that > target in range
337*6777b538SAndroid Build Coastguard Worker // [function_table_entry_start, function_table_entry_end).
338*6777b538SAndroid Build Coastguard Worker const auto first_larger_entry_location = std::upper_bound(
339*6777b538SAndroid Build Coastguard Worker function_table_entry_start, function_table_entry_end,
340*6777b538SAndroid Build Coastguard Worker page_instruction_offset,
341*6777b538SAndroid Build Coastguard Worker [](uint16_t page_instruction_offset, const FunctionTableEntry& entry) {
342*6777b538SAndroid Build Coastguard Worker return page_instruction_offset <
343*6777b538SAndroid Build Coastguard Worker entry.function_start_address_page_instruction_offset;
344*6777b538SAndroid Build Coastguard Worker });
345*6777b538SAndroid Build Coastguard Worker
346*6777b538SAndroid Build Coastguard Worker // Offsets the element found by 1 to get the biggest element that <= target.
347*6777b538SAndroid Build Coastguard Worker const auto entry_location = first_larger_entry_location - 1;
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker // When all offsets in current range > page_instruction_offset (including when
350*6777b538SAndroid Build Coastguard Worker // there is no entry in current range), the `FunctionTableEntry` we are
351*6777b538SAndroid Build Coastguard Worker // looking for is not within the function_offset_table_indices range we are
352*6777b538SAndroid Build Coastguard Worker // inspecting, because the function is too long that it spans multiple pages.
353*6777b538SAndroid Build Coastguard Worker //
354*6777b538SAndroid Build Coastguard Worker // We need to locate the previous entry on function_offset_table_indices and
355*6777b538SAndroid Build Coastguard Worker // find its corresponding page_table index.
356*6777b538SAndroid Build Coastguard Worker //
357*6777b538SAndroid Build Coastguard Worker // Example:
358*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+
359*6777b538SAndroid Build Coastguard Worker // | <-----2 byte-----> | <-----2 byte-----> |
360*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+
361*6777b538SAndroid Build Coastguard Worker // | Page Offset | Offset Table Index |
362*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+-----
363*6777b538SAndroid Build Coastguard Worker // | 10 | XXX | |
364*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+ |
365*6777b538SAndroid Build Coastguard Worker // | ... | ... |Page 0x100
366*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+ |
367*6777b538SAndroid Build Coastguard Worker // | 65500 | ZZZ | |
368*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+----- Page 0x101 is empty
369*6777b538SAndroid Build Coastguard Worker // | 200 | AAA | |
370*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+ |
371*6777b538SAndroid Build Coastguard Worker // | ... | ... |Page 0x102
372*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+ |
373*6777b538SAndroid Build Coastguard Worker // | 65535 | BBB | |
374*6777b538SAndroid Build Coastguard Worker // +--------------------+--------------------+-----
375*6777b538SAndroid Build Coastguard Worker //
376*6777b538SAndroid Build Coastguard Worker // Example:
377*6777b538SAndroid Build Coastguard Worker // For
378*6777b538SAndroid Build Coastguard Worker // - page_number = 0x100, page_instruction_offset >= 65535
379*6777b538SAndroid Build Coastguard Worker // - page_number = 0x101, all page_instruction_offset
380*6777b538SAndroid Build Coastguard Worker // - page_number = 0x102, page_instruction_offset < 200
381*6777b538SAndroid Build Coastguard Worker // We should be able to map them all to entry [65500, ZZZ] in page 0x100.
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker // Finds the page_number that corresponds to `entry_location`. The page
384*6777b538SAndroid Build Coastguard Worker // might not be the page we are inspecting, when the function spans over
385*6777b538SAndroid Build Coastguard Worker // multiple pages.
386*6777b538SAndroid Build Coastguard Worker uint16_t function_start_page_number = page_number;
387*6777b538SAndroid Build Coastguard Worker while (function_offset_table_indices.begin() +
388*6777b538SAndroid Build Coastguard Worker checked_cast<ptrdiff_t>(
389*6777b538SAndroid Build Coastguard Worker page_start_instructions[function_start_page_number]) >
390*6777b538SAndroid Build Coastguard Worker entry_location) {
391*6777b538SAndroid Build Coastguard Worker // First page in page table must not be empty.
392*6777b538SAndroid Build Coastguard Worker DCHECK_NE(function_start_page_number, 0);
393*6777b538SAndroid Build Coastguard Worker function_start_page_number--;
394*6777b538SAndroid Build Coastguard Worker };
395*6777b538SAndroid Build Coastguard Worker
396*6777b538SAndroid Build Coastguard Worker const uint32_t function_start_address_instruction_offset =
397*6777b538SAndroid Build Coastguard Worker (uint32_t{function_start_page_number} << 16) +
398*6777b538SAndroid Build Coastguard Worker entry_location->function_start_address_page_instruction_offset;
399*6777b538SAndroid Build Coastguard Worker
400*6777b538SAndroid Build Coastguard Worker const int instruction_offset_from_function_start =
401*6777b538SAndroid Build Coastguard Worker static_cast<int>((instruction_byte_offset_from_text_section_start >> 1) -
402*6777b538SAndroid Build Coastguard Worker function_start_address_instruction_offset);
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker DCHECK_GE(instruction_offset_from_function_start, 0);
405*6777b538SAndroid Build Coastguard Worker return FunctionOffsetTableIndex{
406*6777b538SAndroid Build Coastguard Worker instruction_offset_from_function_start,
407*6777b538SAndroid Build Coastguard Worker entry_location->function_offset_table_byte_index,
408*6777b538SAndroid Build Coastguard Worker };
409*6777b538SAndroid Build Coastguard Worker }
410*6777b538SAndroid Build Coastguard Worker
411*6777b538SAndroid Build Coastguard Worker } // namespace base
412