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/FIRCLSUnwind_x86.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_X86
25
 
26
static bool FIRCLSCompactUnwindBPFrame(compact_unwind_encoding_t encoding,
27
                                       FIRCLSThreadContext* registers);
28
static bool FIRCLSCompactUnwindFrameless(compact_unwind_encoding_t encoding,
29
                                         FIRCLSThreadContext* registers,
30
                                         uintptr_t functionStart,
31
                                         bool indirect);
32
 
33
#if CLS_COMPACT_UNWINDING_SUPPORTED
34
bool FIRCLSCompactUnwindComputeRegisters(FIRCLSCompactUnwindContext* context,
35
                                         FIRCLSCompactUnwindResult* result,
36
                                         FIRCLSThreadContext* registers) {
37
  if (!FIRCLSIsValidPointer(context) || !FIRCLSIsValidPointer(result) ||
38
      !FIRCLSIsValidPointer(registers)) {
39
    FIRCLSSDKLogError("invalid inputs\n");
40
    return false;
41
  }
42
 
43
  FIRCLSSDKLogDebug("Computing registers for encoding %x\n", result->encoding);
44
 
45
  switch (result->encoding & CLS_X86_MODE_MASK) {
46
    case CLS_X86_MODE_BP_FRAME:
47
      return FIRCLSCompactUnwindBPFrame(result->encoding, registers);
48
    case CLS_X86_MODE_STACK_IMMD:
49
      return FIRCLSCompactUnwindFrameless(result->encoding, registers, result->functionStart,
50
                                          false);
51
    case CLS_X86_MODE_STACK_IND:
52
      return FIRCLSCompactUnwindFrameless(result->encoding, registers, result->functionStart, true);
53
    case CLS_X86_MODE_DWARF:
54
      return FIRCLSCompactUnwindDwarfFrame(context, result->encoding & CLS_X86_DWARF_SECTION_OFFSET,
55
                                           registers);
56
    default:
57
      FIRCLSSDKLogError("Invalid encoding %x\n", result->encoding);
58
      break;
59
  }
60
 
61
  return false;
62
}
63
#endif
64
 
65
static bool FIRCLSCompactUnwindBPFrame(compact_unwind_encoding_t encoding,
66
                                       FIRCLSThreadContext* registers) {
67
  // this is the plain-vanilla frame pointer process
68
 
69
  // uint32_t offset = GET_BITS_WITH_MASK(encoding, UNWIND_X86_EBP_FRAME_OFFSET);
70
  // uint32_t locations = GET_BITS_WITH_MASK(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
71
 
72
  // TODO: pretty sure we do need to restore registers here, so that if a subsequent frame needs
73
  // these results, they will be correct
74
 
75
  // Checkout CompactUnwinder.hpp in libunwind for how to do this. Since we don't make use of any of
76
  // those registers for a stacktrace only, there's nothing we need do with them.
77
 
78
  // read the values from the stack
79
  const uintptr_t framePointer = FIRCLSThreadContextGetFramePointer(registers);
80
  uintptr_t stack[2];
81
 
82
  if (!FIRCLSReadMemory((vm_address_t)framePointer, stack, sizeof(stack))) {
83
    // unable to read the first stack frame
84
    FIRCLSSDKLog("Error: failed to read memory at address %p\n", (void*)framePointer);
85
    return false;
86
  }
87
 
88
  if (!FIRCLSThreadContextSetPC(registers, stack[1])) {
89
    return false;
90
  }
91
 
92
  if (!FIRCLSThreadContextSetFramePointer(registers, stack[0])) {
93
    return false;
94
  }
95
 
96
  if (!FIRCLSThreadContextSetStackPointer(registers,
97
                                          FIRCLSUnwindStackPointerFromFramePointer(framePointer))) {
98
    return false;
99
  }
100
 
101
  return true;
102
}
103
 
104
bool FIRCLSUnwindWithStackScanning(FIRCLSThreadContext* registers) {
105
  vm_address_t start = (vm_address_t)FIRCLSThreadContextGetStackPointer(registers);
106
  vm_address_t end = (vm_address_t)FIRCLSThreadContextGetFramePointer(registers);
107
 
108
  uintptr_t newPC = 0;
109
 
110
  if (!FIRCLSUnwindFirstExecutableAddress(start, end, (vm_address_t*)&newPC)) {
111
    return false;
112
  }
113
 
114
  return FIRCLSThreadContextSetPC(registers, newPC);
115
}
116
 
117
bool FIRCLSUnwindWithFramePointer(FIRCLSThreadContext* registers, bool allowScanning) {
118
  // Here's an interesting case. We've just processed the first frame, and it did
119
  // not have any unwind info. If that first function did not allocate
120
  // a stack frame, we'll "skip" the caller. This might sound unlikely, but it actually
121
  // happens a lot in practice.
122
 
123
  // Sooo, one thing we can do is try to stack the stack for things that look like return
124
  // addresses. Normally, this technique will hit many false positives. But, if we do it
125
  // only for the second frame, and only when we don't have other unwind info available.
126
 
127
  if (allowScanning) {
128
    FIRCLSSDKLogInfo("Attempting stack scan\n");
129
    if (FIRCLSUnwindWithStackScanning(registers)) {
130
      FIRCLSSDKLogInfo("Stack scan successful\n");
131
      return true;
132
    }
133
  }
134
 
135
  // If we ever do anything else with the encoding, we need to be sure
136
  // to set it up right.
137
  return FIRCLSCompactUnwindBPFrame(CLS_X86_MODE_BP_FRAME, registers);
138
}
139
 
140
uintptr_t FIRCLSUnwindStackPointerFromFramePointer(uintptr_t framePtr) {
141
  // the stack pointer is the frame pointer plus the two saved pointers for the frame
142
  return framePtr + 2 * sizeof(void*);
143
}
144
 
145
#if CLS_COMPACT_UNWINDING_SUPPORTED || CLS_DWARF_UNWINDING_SUPPORTED
146
uintptr_t FIRCLSDwarfUnwindGetRegisterValue(const FIRCLSThreadContext* registers, uint64_t num) {
147
  switch (num) {
148
#if CLS_CPU_X86_64
149
    case CLS_DWARF_X86_64_RAX:
150
      return registers->__ss.__rax;
151
    case CLS_DWARF_X86_64_RDX:
152
      return registers->__ss.__rdx;
153
    case CLS_DWARF_X86_64_RCX:
154
      return registers->__ss.__rcx;
155
    case CLS_DWARF_X86_64_RBX:
156
      return registers->__ss.__rbx;
157
    case CLS_DWARF_X86_64_RSI:
158
      return registers->__ss.__rsi;
159
    case CLS_DWARF_X86_64_RDI:
160
      return registers->__ss.__rdi;
161
    case CLS_DWARF_X86_64_RBP:
162
      return registers->__ss.__rbp;
163
    case CLS_DWARF_X86_64_RSP:
164
      return registers->__ss.__rsp;
165
    case CLS_DWARF_X86_64_R8:
166
      return registers->__ss.__r8;
167
    case CLS_DWARF_X86_64_R9:
168
      return registers->__ss.__r9;
169
    case CLS_DWARF_X86_64_R10:
170
      return registers->__ss.__r10;
171
    case CLS_DWARF_X86_64_R11:
172
      return registers->__ss.__r11;
173
    case CLS_DWARF_X86_64_R12:
174
      return registers->__ss.__r12;
175
    case CLS_DWARF_X86_64_R13:
176
      return registers->__ss.__r13;
177
    case CLS_DWARF_X86_64_R14:
178
      return registers->__ss.__r14;
179
    case CLS_DWARF_X86_64_R15:
180
      return registers->__ss.__r15;
181
    case CLS_DWARF_X86_64_RET_ADDR:
182
      return registers->__ss.__rip;
183
#elif CLS_CPU_I386
184
    case CLS_DWARF_X86_EAX:
185
      return registers->__ss.__eax;
186
    case CLS_DWARF_X86_ECX:
187
      return registers->__ss.__ecx;
188
    case CLS_DWARF_X86_EDX:
189
      return registers->__ss.__edx;
190
    case CLS_DWARF_X86_EBX:
191
      return registers->__ss.__ebx;
192
    case CLS_DWARF_X86_EBP:
193
      return registers->__ss.__ebp;
194
    case CLS_DWARF_X86_ESP:
195
      return registers->__ss.__esp;
196
    case CLS_DWARF_X86_ESI:
197
      return registers->__ss.__esi;
198
    case CLS_DWARF_X86_EDI:
199
      return registers->__ss.__edi;
200
    case CLS_DWARF_X86_RET_ADDR:
201
      return registers->__ss.__eip;
202
#endif
203
    default:
204
      break;
205
  }
206
 
207
  FIRCLSSDKLog("Error: Unrecognized get register number %llu\n", num);
208
 
209
  return 0;
210
}
211
 
212
bool FIRCLSDwarfUnwindSetRegisterValue(FIRCLSThreadContext* registers,
213
                                       uint64_t num,
214
                                       uintptr_t value) {
215
  switch (num) {
216
#if CLS_CPU_X86_64
217
    case CLS_DWARF_X86_64_RAX:
218
      registers->__ss.__rax = value;
219
      return true;
220
    case CLS_DWARF_X86_64_RDX:
221
      registers->__ss.__rdx = value;
222
      return true;
223
    case CLS_DWARF_X86_64_RCX:
224
      registers->__ss.__rcx = value;
225
      return true;
226
    case CLS_DWARF_X86_64_RBX:
227
      registers->__ss.__rbx = value;
228
      return true;
229
    case CLS_DWARF_X86_64_RSI:
230
      registers->__ss.__rsi = value;
231
      return true;
232
    case CLS_DWARF_X86_64_RDI:
233
      registers->__ss.__rdi = value;
234
      return true;
235
    case CLS_DWARF_X86_64_RBP:
236
      registers->__ss.__rbp = value;
237
      return true;
238
    case CLS_DWARF_X86_64_RSP:
239
      registers->__ss.__rsp = value;
240
      return true;
241
    case CLS_DWARF_X86_64_R8:
242
      registers->__ss.__r8 = value;
243
      return true;
244
    case CLS_DWARF_X86_64_R9:
245
      registers->__ss.__r9 = value;
246
      return true;
247
    case CLS_DWARF_X86_64_R10:
248
      registers->__ss.__r10 = value;
249
      return true;
250
    case CLS_DWARF_X86_64_R11:
251
      registers->__ss.__r11 = value;
252
      return true;
253
    case CLS_DWARF_X86_64_R12:
254
      registers->__ss.__r12 = value;
255
      return true;
256
    case CLS_DWARF_X86_64_R13:
257
      registers->__ss.__r13 = value;
258
      return true;
259
    case CLS_DWARF_X86_64_R14:
260
      registers->__ss.__r14 = value;
261
      return true;
262
    case CLS_DWARF_X86_64_R15:
263
      registers->__ss.__r15 = value;
264
      return true;
265
    case CLS_DWARF_X86_64_RET_ADDR:
266
      registers->__ss.__rip = value;
267
      return true;
268
#elif CLS_CPU_I386
269
    case CLS_DWARF_X86_EAX:
270
      registers->__ss.__eax = value;
271
      return true;
272
    case CLS_DWARF_X86_ECX:
273
      registers->__ss.__ecx = value;
274
      return true;
275
    case CLS_DWARF_X86_EDX:
276
      registers->__ss.__edx = value;
277
      return true;
278
    case CLS_DWARF_X86_EBX:
279
      registers->__ss.__ebx = value;
280
      return true;
281
    case CLS_DWARF_X86_EBP:
282
      registers->__ss.__ebp = value;
283
      return true;
284
    case CLS_DWARF_X86_ESP:
285
      registers->__ss.__esp = value;
286
      return true;
287
    case CLS_DWARF_X86_ESI:
288
      registers->__ss.__esi = value;
289
      return true;
290
    case CLS_DWARF_X86_EDI:
291
      registers->__ss.__edi = value;
292
      return true;
293
    case CLS_DWARF_X86_RET_ADDR:
294
      registers->__ss.__eip = value;
295
      return true;
296
#endif
297
    default:
298
      break;
299
  }
300
 
301
  FIRCLSSDKLog("Unrecognized set register number %llu\n", num);
302
 
303
  return false;
304
}
305
#endif
306
 
307
#if CLS_COMPACT_UNWINDING_SUPPORTED
308
bool FIRCLSCompactUnwindComputeStackSize(const compact_unwind_encoding_t encoding,
309
                                         const uintptr_t functionStart,
310
                                         const bool indirect,
311
                                         uint32_t* const stackSize) {
312
  if (!FIRCLSIsValidPointer(stackSize)) {
313
    FIRCLSSDKLog("Error: invalid inputs\n");
314
    return false;
315
  }
316
 
317
  const uint32_t stackSizeEncoded = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_SIZE);
318
 
319
  if (!indirect) {
320
    *stackSize = stackSizeEncoded * sizeof(void*);
321
    return true;
322
  }
323
 
324
  const vm_address_t sublAddress = functionStart + stackSizeEncoded;
325
  uint32_t sublValue = 0;
326
 
327
  if (!FIRCLSReadMemory(sublAddress, &sublValue, sizeof(uint32_t))) {
328
    FIRCLSSDKLog("Error: unable to read subl value\n");
329
    return false;
330
  }
331
 
332
  const uint32_t stackAdjust = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_ADJUST);
333
 
334
  *stackSize = sublValue + stackAdjust * sizeof(void*);
335
 
336
  return true;
337
}
338
 
339
bool FIRCLSCompactUnwindDecompressPermutation(const compact_unwind_encoding_t encoding,
340
                                              uintptr_t permutatedRegisters[const static 6]) {
341
  const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT);
342
  uint32_t permutation = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_PERMUTATION);
343
 
344
  switch (regCount) {
345
    case 6:
346
      permutatedRegisters[0] = permutation / 120;
347
      permutation -= (permutatedRegisters[0] * 120);
348
      permutatedRegisters[1] = permutation / 24;
349
      permutation -= (permutatedRegisters[1] * 24);
350
      permutatedRegisters[2] = permutation / 6;
351
      permutation -= (permutatedRegisters[2] * 6);
352
      permutatedRegisters[3] = permutation / 2;
353
      permutation -= (permutatedRegisters[3] * 2);
354
      permutatedRegisters[4] = permutation;
355
      permutatedRegisters[5] = 0;
356
      break;
357
    case 5:
358
      permutatedRegisters[0] = permutation / 120;
359
      permutation -= (permutatedRegisters[0] * 120);
360
      permutatedRegisters[1] = permutation / 24;
361
      permutation -= (permutatedRegisters[1] * 24);
362
      permutatedRegisters[2] = permutation / 6;
363
      permutation -= (permutatedRegisters[2] * 6);
364
      permutatedRegisters[3] = permutation / 2;
365
      permutation -= (permutatedRegisters[3] * 2);
366
      permutatedRegisters[4] = permutation;
367
      break;
368
    case 4:
369
      permutatedRegisters[0] = permutation / 60;
370
      permutation -= (permutatedRegisters[0] * 60);
371
      permutatedRegisters[1] = permutation / 12;
372
      permutation -= (permutatedRegisters[1] * 12);
373
      permutatedRegisters[2] = permutation / 3;
374
      permutation -= (permutatedRegisters[2] * 3);
375
      permutatedRegisters[3] = permutation;
376
      break;
377
    case 3:
378
      permutatedRegisters[0] = permutation / 20;
379
      permutation -= (permutatedRegisters[0] * 20);
380
      permutatedRegisters[1] = permutation / 4;
381
      permutation -= (permutatedRegisters[1] * 4);
382
      permutatedRegisters[2] = permutation;
383
      break;
384
    case 2:
385
      permutatedRegisters[0] = permutation / 5;
386
      permutation -= (permutatedRegisters[0] * 5);
387
      permutatedRegisters[1] = permutation;
388
      break;
389
    case 1:
390
      permutatedRegisters[0] = permutation;
391
      break;
392
    case 0:
393
      break;
394
    default:
395
      FIRCLSSDKLog("Error: unhandled number of register permutations for encoding %x\n", encoding);
396
      return false;
397
  }
398
 
399
  return true;
400
}
401
 
402
bool FIRCLSCompactUnwindRemapRegisters(const compact_unwind_encoding_t encoding,
403
                                       uintptr_t permutatedRegisters[const static 6],
404
                                       uintptr_t savedRegisters[const static 6]) {
405
  const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT);
406
 
407
  if (regCount > 6) {
408
    FIRCLSSDKLog("Error: invalid register number count %d\n", regCount);
409
    return false;
410
  }
411
 
412
  // Re-number the registers
413
 
414
  // You are probably wondering, what the hell is this algorithm even doing? It is
415
  // taken from libunwind's implemenation that does the same thing.
416
  bool used[7] = {false, false, false, false, false, false, false};
417
  for (uint32_t i = 0; i < regCount; ++i) {
418
    int renum = 0;
419
    for (int u = 1; u < 7; ++u) {
420
      if (!used[u]) {
421
        if (renum == permutatedRegisters[i]) {
422
          savedRegisters[i] = u;
423
          used[u] = true;
424
          break;
425
        }
426
        ++renum;
427
      }
428
    }
429
  }
430
 
431
  return true;
432
}
433
 
434
bool FIRCLSCompactUnwindRestoreRegisters(compact_unwind_encoding_t encoding,
435
                                         FIRCLSThreadContext* registers,
436
                                         uint32_t stackSize,
437
                                         const uintptr_t savedRegisters[const static 6],
438
                                         uintptr_t* address) {
439
  if (!FIRCLSIsValidPointer(registers) || !FIRCLSIsValidPointer(address)) {
440
    FIRCLSSDKLog("Error: invalid inputs\n");
441
    return false;
442
  }
443
 
444
  const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT);
445
 
446
  // compute initial address of saved registers
447
  *address = FIRCLSThreadContextGetStackPointer(registers) + stackSize - sizeof(void*) -
448
             sizeof(void*) * regCount;
449
  uintptr_t value = 0;
450
 
451
  for (uint32_t i = 0; i < regCount; ++i) {
452
    value = 0;
453
 
454
    switch (savedRegisters[i]) {
455
      case CLS_X86_REG_RBP:
456
        if (!FIRCLSReadMemory((vm_address_t)*address, (void*)&value, sizeof(uintptr_t))) {
457
          FIRCLSSDKLog("Error: unable to read memory to set register\n");
458
          return false;
459
        }
460
 
461
        if (!FIRCLSThreadContextSetFramePointer(registers, value)) {
462
          FIRCLSSDKLog("Error: unable to set FP\n");
463
          return false;
464
        }
465
        break;
466
      default:
467
        // here, we are restoring a register we don't need for unwinding
468
        FIRCLSSDKLog("Error: skipping a restore of register %d at %p\n", (int)savedRegisters[i],
469
                     (void*)*address);
470
        break;
471
    }
472
 
473
    *address += sizeof(void*);
474
  }
475
 
476
  return true;
477
}
478
 
479
static bool FIRCLSCompactUnwindFrameless(compact_unwind_encoding_t encoding,
480
                                         FIRCLSThreadContext* registers,
481
                                         uintptr_t functionStart,
482
                                         bool indirect) {
483
  FIRCLSSDKLog("Frameless unwind encountered with encoding %x\n", encoding);
484
 
485
  uint32_t stackSize = 0;
486
  if (!FIRCLSCompactUnwindComputeStackSize(encoding, functionStart, indirect, &stackSize)) {
487
    FIRCLSSDKLog("Error: unable to compute stack size for encoding %x\n", encoding);
488
    return false;
489
  }
490
 
491
  uintptr_t permutatedRegisters[6];
492
 
493
  memset(permutatedRegisters, 0, sizeof(permutatedRegisters));
494
  if (!FIRCLSCompactUnwindDecompressPermutation(encoding, permutatedRegisters)) {
495
    FIRCLSSDKLog("Error: unable to decompress registers %x\n", encoding);
496
    return false;
497
  }
498
 
499
  uintptr_t savedRegisters[6];
500
 
501
  memset(savedRegisters, 0, sizeof(savedRegisters));
502
  if (!FIRCLSCompactUnwindRemapRegisters(encoding, permutatedRegisters, savedRegisters)) {
503
    FIRCLSSDKLog("Error: unable to remap registers %x\n", encoding);
504
    return false;
505
  }
506
 
507
  uintptr_t address = 0;
508
 
509
  if (!FIRCLSCompactUnwindRestoreRegisters(encoding, registers, stackSize, savedRegisters,
510
                                           &address)) {
511
    FIRCLSSDKLog("Error: unable to restore registers\n");
512
    return false;
513
  }
514
 
515
  FIRCLSSDKLog("SP is %p and we are reading %p\n",
516
               (void*)FIRCLSThreadContextGetStackPointer(registers), (void*)address);
517
  // read the value from the stack, now that we know the address to read
518
  uintptr_t value = 0;
519
  if (!FIRCLSReadMemory((vm_address_t)address, (void*)&value, sizeof(uintptr_t))) {
520
    FIRCLSSDKLog("Error: unable to read memory to set register\n");
521
    return false;
522
  }
523
 
524
  FIRCLSSDKLog("Read PC to be %p\n", (void*)value);
525
  if (!FIRCLSIsValidPointer(value)) {
526
    FIRCLSSDKLog("Error: computed PC is invalid\n");
527
    return false;
528
  }
529
 
530
  return FIRCLSThreadContextSetPC(registers, value) &&
531
         FIRCLSThreadContextSetStackPointer(registers, address + sizeof(void*));
532
}
533
#endif
534
 
535
#else
536
INJECT_STRIP_SYMBOL(unwind_x86)
537
#endif