Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h"
16
#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h"
17
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
18
#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h"
19
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
20
#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h"
21
#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h"
22
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
23
 
24
#if CLS_CPU_ARM || CLS_CPU_ARM64
25
 
26
static bool FIRCLSUnwindWithLRRegister(FIRCLSThreadContext* registers) {
27
  if (!FIRCLSIsValidPointer(registers)) {
28
    return false;
29
  }
30
 
31
  // Return address is in LR, SP is pointing to the next frame.
32
  uintptr_t value = FIRCLSThreadContextGetLinkRegister(registers);
33
 
34
  if (!FIRCLSIsValidPointer(value)) {
35
    FIRCLSSDKLog("Error: LR value is invalid\n");
36
    return false;
37
  }
38
 
39
  return FIRCLSThreadContextSetPC(registers, value);
40
}
41
 
42
bool FIRCLSUnwindWithFramePointer(FIRCLSThreadContext* registers, bool allowScanning) {
43
  if (allowScanning) {
44
    // The LR register does have the return address here, but there are situations where
45
    // this can produce false matches. Better backend rules can fix this up in many cases.
46
    if (FIRCLSUnwindWithLRRegister(registers)) {
47
      return true;
48
    } else {
49
      // In this case, we're unable to use the LR. We don't want to just stop unwinding, so
50
      // proceed with the normal, non-scanning path
51
      FIRCLSSDKLog("Unable to use LR, skipping\n");
52
    }
53
  }
54
 
55
  // read the values from the stack
56
  const uintptr_t framePointer = FIRCLSThreadContextGetFramePointer(registers);
57
  uintptr_t stack[2];
58
 
59
  if (!FIRCLSReadMemory((vm_address_t)framePointer, stack, sizeof(stack))) {
60
    // unable to read the first stack frame
61
    FIRCLSSDKLog("Error: failed to read memory at address %p\n", (void*)framePointer);
62
    return false;
63
  }
64
 
65
  if (!FIRCLSThreadContextSetPC(registers, stack[1])) {
66
    return false;
67
  }
68
 
69
  if (!FIRCLSThreadContextSetFramePointer(registers, stack[0])) {
70
    return false;
71
  }
72
 
73
  if (!FIRCLSThreadContextSetStackPointer(registers,
74
                                          FIRCLSUnwindStackPointerFromFramePointer(framePointer))) {
75
    return false;
76
  }
77
 
78
  return true;
79
}
80
 
81
uintptr_t FIRCLSUnwindStackPointerFromFramePointer(uintptr_t framePtr) {
82
  // the stack pointer is the frame pointer plus the two saved pointers for the frame
83
  return framePtr + 2 * sizeof(void*);
84
}
85
 
86
#if CLS_COMPACT_UNWINDING_SUPPORTED
87
bool FIRCLSCompactUnwindComputeRegisters(FIRCLSCompactUnwindContext* context,
88
                                         FIRCLSCompactUnwindResult* result,
89
                                         FIRCLSThreadContext* registers) {
90
  if (!context || !result || !registers) {
91
    return false;
92
  }
93
 
94
  // Note that compact_uwnind_encoding.h has a few bugs in it prior to iOS 8.0.
95
  // Only refer to the >= 8.0 header.
96
  switch (result->encoding & UNWIND_ARM64_MODE_MASK) {
97
    case UNWIND_ARM64_MODE_FRAMELESS:
98
      // Interestingly, we also know the size of the stack frame, by
99
      // using UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. Is that useful?
100
      return FIRCLSUnwindWithLRRegister(registers);
101
      break;
102
    case UNWIND_ARM64_MODE_DWARF:
103
      return FIRCLSCompactUnwindDwarfFrame(
104
          context, result->encoding & UNWIND_ARM64_DWARF_SECTION_OFFSET, registers);
105
      break;
106
    case UNWIND_ARM64_MODE_FRAME:
107
      return FIRCLSUnwindWithFramePointer(registers, false);
108
    default:
109
      FIRCLSSDKLog("Invalid encoding 0x%x\n", result->encoding);
110
      break;
111
  }
112
 
113
  return false;
114
}
115
#endif
116
 
117
#if CLS_DWARF_UNWINDING_SUPPORTED
118
uintptr_t FIRCLSDwarfUnwindGetRegisterValue(const FIRCLSThreadContext* registers, uint64_t num) {
119
  switch (num) {
120
    case CLS_DWARF_ARM64_X0:
121
      return registers->__ss.__x[0];
122
    case CLS_DWARF_ARM64_X1:
123
      return registers->__ss.__x[1];
124
    case CLS_DWARF_ARM64_X2:
125
      return registers->__ss.__x[2];
126
    case CLS_DWARF_ARM64_X3:
127
      return registers->__ss.__x[3];
128
    case CLS_DWARF_ARM64_X4:
129
      return registers->__ss.__x[4];
130
    case CLS_DWARF_ARM64_X5:
131
      return registers->__ss.__x[5];
132
    case CLS_DWARF_ARM64_X6:
133
      return registers->__ss.__x[6];
134
    case CLS_DWARF_ARM64_X7:
135
      return registers->__ss.__x[7];
136
    case CLS_DWARF_ARM64_X8:
137
      return registers->__ss.__x[8];
138
    case CLS_DWARF_ARM64_X9:
139
      return registers->__ss.__x[9];
140
    case CLS_DWARF_ARM64_X10:
141
      return registers->__ss.__x[10];
142
    case CLS_DWARF_ARM64_X11:
143
      return registers->__ss.__x[11];
144
    case CLS_DWARF_ARM64_X12:
145
      return registers->__ss.__x[12];
146
    case CLS_DWARF_ARM64_X13:
147
      return registers->__ss.__x[13];
148
    case CLS_DWARF_ARM64_X14:
149
      return registers->__ss.__x[14];
150
    case CLS_DWARF_ARM64_X15:
151
      return registers->__ss.__x[15];
152
    case CLS_DWARF_ARM64_X16:
153
      return registers->__ss.__x[16];
154
    case CLS_DWARF_ARM64_X17:
155
      return registers->__ss.__x[17];
156
    case CLS_DWARF_ARM64_X18:
157
      return registers->__ss.__x[18];
158
    case CLS_DWARF_ARM64_X19:
159
      return registers->__ss.__x[19];
160
    case CLS_DWARF_ARM64_X20:
161
      return registers->__ss.__x[20];
162
    case CLS_DWARF_ARM64_X21:
163
      return registers->__ss.__x[21];
164
    case CLS_DWARF_ARM64_X22:
165
      return registers->__ss.__x[22];
166
    case CLS_DWARF_ARM64_X23:
167
      return registers->__ss.__x[23];
168
    case CLS_DWARF_ARM64_X24:
169
      return registers->__ss.__x[24];
170
    case CLS_DWARF_ARM64_X25:
171
      return registers->__ss.__x[25];
172
    case CLS_DWARF_ARM64_X26:
173
      return registers->__ss.__x[26];
174
    case CLS_DWARF_ARM64_X27:
175
      return registers->__ss.__x[27];
176
    case CLS_DWARF_ARM64_X28:
177
      return registers->__ss.__x[28];
178
    case CLS_DWARF_ARM64_FP:
179
      return FIRCLSThreadContextGetFramePointer(registers);
180
    case CLS_DWARF_ARM64_LR:
181
      return FIRCLSThreadContextGetLinkRegister(registers);
182
    case CLS_DWARF_ARM64_SP:
183
      return FIRCLSThreadContextGetStackPointer(registers);
184
    default:
185
      break;
186
  }
187
 
188
  FIRCLSSDKLog("Error: Unrecognized get register number %llu\n", num);
189
 
190
  return 0;
191
}
192
 
193
bool FIRCLSDwarfUnwindSetRegisterValue(FIRCLSThreadContext* registers,
194
                                       uint64_t num,
195
                                       uintptr_t value) {
196
  switch (num) {
197
    case CLS_DWARF_ARM64_X0:
198
      registers->__ss.__x[0] = value;
199
      return true;
200
    case CLS_DWARF_ARM64_X1:
201
      registers->__ss.__x[1] = value;
202
      return true;
203
    case CLS_DWARF_ARM64_X2:
204
      registers->__ss.__x[2] = value;
205
      return true;
206
    case CLS_DWARF_ARM64_X3:
207
      registers->__ss.__x[3] = value;
208
      return true;
209
    case CLS_DWARF_ARM64_X4:
210
      registers->__ss.__x[4] = value;
211
      return true;
212
    case CLS_DWARF_ARM64_X5:
213
      registers->__ss.__x[5] = value;
214
      return true;
215
    case CLS_DWARF_ARM64_X6:
216
      registers->__ss.__x[6] = value;
217
      return true;
218
    case CLS_DWARF_ARM64_X7:
219
      registers->__ss.__x[7] = value;
220
      return true;
221
    case CLS_DWARF_ARM64_X8:
222
      registers->__ss.__x[8] = value;
223
      return true;
224
    case CLS_DWARF_ARM64_X9:
225
      registers->__ss.__x[9] = value;
226
      return true;
227
    case CLS_DWARF_ARM64_X10:
228
      registers->__ss.__x[10] = value;
229
      return true;
230
    case CLS_DWARF_ARM64_X11:
231
      registers->__ss.__x[11] = value;
232
      return true;
233
    case CLS_DWARF_ARM64_X12:
234
      registers->__ss.__x[12] = value;
235
      return true;
236
    case CLS_DWARF_ARM64_X13:
237
      registers->__ss.__x[13] = value;
238
      return true;
239
    case CLS_DWARF_ARM64_X14:
240
      registers->__ss.__x[14] = value;
241
      return true;
242
    case CLS_DWARF_ARM64_X15:
243
      registers->__ss.__x[15] = value;
244
      return true;
245
    case CLS_DWARF_ARM64_X16:
246
      registers->__ss.__x[16] = value;
247
      return true;
248
    case CLS_DWARF_ARM64_X17:
249
      registers->__ss.__x[17] = value;
250
      return true;
251
    case CLS_DWARF_ARM64_X18:
252
      registers->__ss.__x[18] = value;
253
      return true;
254
    case CLS_DWARF_ARM64_X19:
255
      registers->__ss.__x[19] = value;
256
      return true;
257
    case CLS_DWARF_ARM64_X20:
258
      registers->__ss.__x[20] = value;
259
      return true;
260
    case CLS_DWARF_ARM64_X21:
261
      registers->__ss.__x[21] = value;
262
      return true;
263
    case CLS_DWARF_ARM64_X22:
264
      registers->__ss.__x[22] = value;
265
      return true;
266
    case CLS_DWARF_ARM64_X23:
267
      registers->__ss.__x[23] = value;
268
      return true;
269
    case CLS_DWARF_ARM64_X24:
270
      registers->__ss.__x[24] = value;
271
      return true;
272
    case CLS_DWARF_ARM64_X25:
273
      registers->__ss.__x[25] = value;
274
      return true;
275
    case CLS_DWARF_ARM64_X26:
276
      registers->__ss.__x[26] = value;
277
      return true;
278
    case CLS_DWARF_ARM64_X27:
279
      registers->__ss.__x[27] = value;
280
      return true;
281
    case CLS_DWARF_ARM64_X28:
282
      registers->__ss.__x[28] = value;
283
      return true;
284
    case CLS_DWARF_ARM64_FP:
285
      FIRCLSThreadContextSetFramePointer(registers, value);
286
      return true;
287
    case CLS_DWARF_ARM64_SP:
288
      FIRCLSThreadContextSetStackPointer(registers, value);
289
      return true;
290
    case CLS_DWARF_ARM64_LR:
291
      // Here's what's going on. For x86, the "return register" is virtual. The architecture
292
      // doesn't actually have one, but DWARF does have the concept. So, when the system
293
      // tries to set the return register, we set the PC. You can see this behavior
294
      // in the FIRCLSDwarfUnwindSetRegisterValue implemenation for that architecture. In the
295
      // case of ARM64, the register is real. So, we have to be extra careful to make sure
296
      // we update the PC here. Otherwise, when a DWARF unwind completes, it won't have
297
      // changed the PC to the right value.
298
      FIRCLSThreadContextSetLinkRegister(registers, value);
299
      FIRCLSThreadContextSetPC(registers, value);
300
      return true;
301
    default:
302
      break;
303
  }
304
 
305
  FIRCLSSDKLog("Unrecognized set register number %llu\n", num);
306
 
307
  return false;
308
}
309
#endif
310
 
311
#else
312
INJECT_STRIP_SYMBOL(unwind_arm)
313
#endif