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/Dwarf/FIRCLSDwarfUnwind.h"
16
#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h"
17
#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
18
#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h"
19
#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
20
#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h"
21
#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
22
#include "Crashlytics/third_party/libunwind/dwarf.h"
23
 
24
#include <string.h>
25
 
26
#if CLS_DWARF_UNWINDING_SUPPORTED
27
 
28
#define FIRCLSDwarfLog(__FORMAT__, ...) FIRCLSSDKLog(__FORMAT__, ##__VA_ARGS__)
29
 
30
#define CLS_DWARF_EXPRESSION_STACK_SIZE (100)
31
 
32
#pragma mark Prototypes
33
static bool FIRCLSDwarfParseAndProcessAugmentation(DWARFCIERecord* record, const void** ptr);
34
 
35
#pragma mark - Record Parsing
36
bool FIRCLSDwarfParseCIERecord(DWARFCIERecord* cie, const void* ptr) {
37
  if (!cie || !ptr) {
38
    return false;
39
  }
40
 
41
  memset(cie, 0, sizeof(DWARFCIERecord));
42
 
43
  cie->length = FIRCLSParseRecordLengthAndAdvance(&ptr);
44
  if (cie->length == 0) {
45
    FIRCLSSDKLog("Error: CIE length invalid\n");
46
    return false;
47
  }
48
 
49
  // the length does not include the length field(s) themselves
50
  const void* endAddress = ptr + cie->length;
51
 
52
  if (FIRCLSParseUint32AndAdvance(&ptr) != DWARF_CIE_ID_CIE_FLAG) {
53
    FIRCLSSDKLog("Error: CIE flag not found\n");
54
  }
55
 
56
  cie->version = FIRCLSParseUint8AndAdvance(&ptr);
57
  if (cie->version != 1 && cie->version != 3) {
58
    FIRCLSSDKLog("Error: CIE version %u unsupported\n", cie->version);
59
  }
60
 
61
  cie->pointerEncoding = DW_EH_PE_absptr;
62
  cie->lsdaEncoding = DW_EH_PE_absptr;
63
 
64
  cie->augmentation = FIRCLSParseStringAndAdvance(&ptr);
65
  cie->codeAlignFactor = FIRCLSParseULEB128AndAdvance(&ptr);
66
  cie->dataAlignFactor = FIRCLSParseLEB128AndAdvance(&ptr);
67
 
68
  switch (cie->version) {
69
    case 1:
70
      cie->returnAddressRegister = FIRCLSParseUint8AndAdvance(&ptr);
71
      break;
72
    case 3:
73
      cie->returnAddressRegister = FIRCLSParseULEB128AndAdvance(&ptr);
74
      break;
75
    default:
76
      FIRCLSSDKLog("Error: CIE version %u unsupported\n", cie->version);
77
      return false;
78
  }
79
 
80
  if (!FIRCLSDwarfParseAndProcessAugmentation(cie, &ptr)) {
81
    return false;
82
  }
83
 
84
  cie->instructions.data = ptr;
85
  cie->instructions.length = (uint32_t)(endAddress - ptr);
86
 
87
  return true;
88
}
89
 
90
static bool FIRCLSDwarfParseAndProcessAugmentation(DWARFCIERecord* record, const void** ptr) {
91
  if (!record || !ptr) {
92
    return false;
93
  }
94
 
95
  if (!record->augmentation) {
96
    return false;
97
  }
98
 
99
  if (record->augmentation[0] == 0) {
100
    return true;
101
  }
102
 
103
  if (record->augmentation[0] != 'z') {
104
    FIRCLSSDKLog("Error: Unimplemented: augmentation string %s\n", record->augmentation);
105
    return false;
106
  }
107
 
108
  size_t stringLength = strlen(record->augmentation);
109
 
110
  uint64_t dataLength = FIRCLSParseULEB128AndAdvance(ptr);
111
  const void* ending = *ptr + dataLength;
112
 
113
  // start at 1 because we know the first character is a 'z'
114
  for (size_t i = 1; i < stringLength; ++i) {
115
    switch (record->augmentation[i]) {
116
      case 'L':
117
        // There is an LSDA pointer encoding present.  The actual address of the LSDA
118
        // is in the FDE
119
        record->lsdaEncoding = FIRCLSParseUint8AndAdvance(ptr);
120
        break;
121
      case 'R':
122
        // There is a pointer encoding present, used for all addresses in an FDE.
123
        record->pointerEncoding = FIRCLSParseUint8AndAdvance(ptr);
124
        break;
125
      case 'P':
126
        // Two arguments.  A pointer encoding, and a pointer to a personality function encoded
127
        // with that value.
128
        record->personalityEncoding = FIRCLSParseUint8AndAdvance(ptr);
129
        record->personalityFunction =
130
            FIRCLSParseAddressWithEncodingAndAdvance(ptr, record->personalityEncoding);
131
        if (record->personalityFunction == CLS_INVALID_ADDRESS) {
132
          FIRCLSSDKLog("Error: Found an invalid start address\n");
133
          return false;
134
        }
135
        break;
136
      case 'S':
137
        record->signalFrame = true;
138
        break;
139
      default:
140
        FIRCLSSDKLog("Error: Unhandled augmentation string entry %c\n", record->augmentation[i]);
141
        return false;
142
    }
143
 
144
    // small sanity check
145
    if (*ptr > ending) {
146
      return false;
147
    }
148
  }
149
 
150
  return true;
151
}
152
 
153
bool FIRCLSDwarfParseFDERecord(DWARFFDERecord* fdeRecord,
154
                               bool parseCIE,
155
                               DWARFCIERecord* cieRecord,
156
                               const void* ptr) {
157
  if (!fdeRecord || !cieRecord || !ptr) {
158
    return false;
159
  }
160
 
161
  fdeRecord->length = FIRCLSParseRecordLengthAndAdvance(&ptr);
162
  if (fdeRecord->length == 0) {
163
    FIRCLSSDKLog("Error: FDE has zero length\n");
164
    return false;
165
  }
166
 
167
  // length does not include length field
168
  const void* endAddress = ptr + fdeRecord->length;
169
 
170
  // According to the spec, this is 32/64 bit value, but libunwind always
171
  // parses this as a 32bit value.
172
  fdeRecord->cieOffset = FIRCLSParseUint32AndAdvance(&ptr);
173
  if (fdeRecord->cieOffset == 0) {
174
    FIRCLSSDKLog("Error: CIE offset invalid\n");
175
    return false;
176
  }
177
 
178
  if (parseCIE) {
179
    // The CIE offset is really weird. It appears to be an offset from the
180
    // beginning of its field. This isn't what the documentation says, but it is
181
    // a little ambigious. This is what DwarfParser.hpp does.
182
    // Note that we have to back up one sizeof(uint32_t), because we've advanced
183
    // by parsing the offset
184
    const void* ciePointer = ptr - fdeRecord->cieOffset - sizeof(uint32_t);
185
    if (!FIRCLSDwarfParseCIERecord(cieRecord, ciePointer)) {
186
      FIRCLSSDKLog("Error: Unable to parse CIE record\n");
187
      return false;
188
    }
189
  }
190
 
191
  if (!FIRCLSDwarfCIEIsValid(cieRecord)) {
192
    FIRCLSSDKLog("Error: CIE invalid\n");
193
    return false;
194
  }
195
 
196
  // the next field depends on the pointer encoding style used
197
  fdeRecord->startAddress =
198
      FIRCLSParseAddressWithEncodingAndAdvance(&ptr, cieRecord->pointerEncoding);
199
  if (fdeRecord->startAddress == CLS_INVALID_ADDRESS) {
200
    FIRCLSSDKLog("Error: Found an invalid start address\n");
201
    return false;
202
  }
203
 
204
  // Here's something weird too. The range is encoded as a "special" address, where only the value
205
  // is used, regardless of other pointer-encoding schemes.
206
  fdeRecord->rangeSize = FIRCLSParseAddressWithEncodingAndAdvance(
207
      &ptr, cieRecord->pointerEncoding & DW_EH_PE_VALUE_MASK);
208
  if (fdeRecord->rangeSize == CLS_INVALID_ADDRESS) {
209
    FIRCLSSDKLog("Error: Found an invalid address range\n");
210
    return false;
211
  }
212
 
213
  // Just skip over the section for now. The data here is only needed for personality functions,
214
  // which we don't need
215
  if (FIRCLSDwarfCIEHasAugmentationData(cieRecord)) {
216
    uintptr_t augmentationLength = (uintptr_t)FIRCLSParseULEB128AndAdvance(&ptr);
217
 
218
    ptr += augmentationLength;
219
  }
220
 
221
  fdeRecord->instructions.data = ptr;
222
  fdeRecord->instructions.length = (uint32_t)(endAddress - ptr);
223
 
224
  return true;
225
}
226
 
227
bool FIRCLSDwarfParseCFIFromFDERecord(FIRCLSDwarfCFIRecord* record, const void* ptr) {
228
  if (!record || !ptr) {
229
    return false;
230
  }
231
 
232
  return FIRCLSDwarfParseFDERecord(&record->fde, true, &record->cie, ptr);
233
}
234
 
235
bool FIRCLSDwarfParseCFIFromFDERecordOffset(FIRCLSDwarfCFIRecord* record,
236
                                            const void* ehFrame,
237
                                            uintptr_t fdeOffset) {
238
  if (!record || !ehFrame || (fdeOffset == 0)) {
239
    return false;
240
  }
241
 
242
  const void* ptr = ehFrame + fdeOffset;
243
 
244
  return FIRCLSDwarfParseCFIFromFDERecord(record, ptr);
245
}
246
 
247
#pragma mark - Properties
248
bool FIRCLSDwarfCIEIsValid(DWARFCIERecord* cie) {
249
  if (!cie) {
250
    return false;
251
  }
252
 
253
  if (cie->length == 0) {
254
    return false;
255
  }
256
 
257
  if (cie->version != 1 && cie->version != 3) {
258
    return false;
259
  }
260
 
261
  return true;
262
}
263
 
264
bool FIRCLSDwarfCIEHasAugmentationData(DWARFCIERecord* cie) {
265
  if (!cie) {
266
    return false;
267
  }
268
 
269
  if (!cie->augmentation) {
270
    return false;
271
  }
272
 
273
  return cie->augmentation[0] == 'z';
274
}
275
 
276
#pragma mark - Instructions
277
 
278
static bool FIRCLSDwarfParseAndExecute_set_loc(const void** cursor,
279
                                               DWARFCIERecord* cieRecord,
280
                                               intptr_t* codeOffset) {
281
  uintptr_t operand = FIRCLSParseAddressWithEncodingAndAdvance(cursor, cieRecord->pointerEncoding);
282
 
283
  *codeOffset = operand;
284
 
285
  FIRCLSDwarfLog("DW_CFA_set_loc %lu\n", operand);
286
 
287
  return true;
288
}
289
 
290
static bool FIRCLSDwarfParseAndExecute_advance_loc1(const void** cursor,
291
                                                    DWARFCIERecord* cieRecord,
292
                                                    intptr_t* codeOffset) {
293
  int64_t offset = FIRCLSParseUint8AndAdvance(cursor) * cieRecord->codeAlignFactor;
294
 
295
  *codeOffset += offset;
296
 
297
  FIRCLSDwarfLog("DW_CFA_advance_loc1 %lld\n", offset);
298
 
299
  return true;
300
}
301
 
302
static bool FIRCLSDwarfParseAndExecute_advance_loc2(const void** cursor,
303
                                                    DWARFCIERecord* cieRecord,
304
                                                    intptr_t* codeOffset) {
305
  int64_t offset = FIRCLSParseUint16AndAdvance(cursor) * cieRecord->codeAlignFactor;
306
 
307
  *codeOffset += offset;
308
 
309
  FIRCLSDwarfLog("DW_CFA_advance_loc2 %lld\n", offset);
310
 
311
  return true;
312
}
313
 
314
static bool FIRCLSDwarfParseAndExecute_advance_loc4(const void** cursor,
315
                                                    DWARFCIERecord* cieRecord,
316
                                                    intptr_t* codeOffset) {
317
  int64_t offset = FIRCLSParseUint32AndAdvance(cursor) * cieRecord->codeAlignFactor;
318
 
319
  *codeOffset += offset;
320
 
321
  FIRCLSDwarfLog("DW_CFA_advance_loc4 %lld\n", offset);
322
 
323
  return true;
324
}
325
 
326
static bool FIRCLSDwarfParseAndExecute_def_cfa(const void** cursor,
327
                                               DWARFCIERecord* cieRecord,
328
                                               FIRCLSDwarfState* state) {
329
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
330
 
331
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
332
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_def_cfa register number\n");
333
    return false;
334
  }
335
 
336
  int64_t offset = FIRCLSParseULEB128AndAdvance(cursor);
337
 
338
  state->cfaRegister = regNum;
339
  state->cfaRegisterOffset = offset;
340
 
341
  FIRCLSDwarfLog("DW_CFA_def_cfa %llu, %lld\n", regNum, offset);
342
 
343
  return true;
344
}
345
 
346
static bool FIRCLSDwarfParseAndExecute_def_cfa_register(const void** cursor,
347
                                                        DWARFCIERecord* cieRecord,
348
                                                        FIRCLSDwarfState* state) {
349
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
350
 
351
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
352
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_def_cfa_register register number\n");
353
    return false;
354
  }
355
 
356
  state->cfaRegister = regNum;
357
 
358
  FIRCLSDwarfLog("DW_CFA_def_cfa_register %llu\n", regNum);
359
 
360
  return true;
361
}
362
 
363
static bool FIRCLSDwarfParseAndExecute_def_cfa_offset(const void** cursor,
364
                                                      DWARFCIERecord* cieRecord,
365
                                                      FIRCLSDwarfState* state) {
366
  uint64_t offset = FIRCLSParseULEB128AndAdvance(cursor);
367
 
368
  state->cfaRegisterOffset = offset;
369
 
370
  FIRCLSDwarfLog("DW_CFA_def_cfa_offset %lld\n", offset);
371
 
372
  return true;
373
}
374
 
375
static bool FIRCLSDwarfParseAndExecute_same_value(const void** cursor,
376
                                                  DWARFCIERecord* cieRecord,
377
                                                  FIRCLSDwarfState* state) {
378
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
379
 
380
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
381
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_same_value register number\n");
382
    return false;
383
  }
384
 
385
  state->registers[regNum].location = FIRCLSDwarfRegisterUnused;
386
 
387
  FIRCLSDwarfLog("DW_CFA_same_value %llu\n", regNum);
388
 
389
  return true;
390
}
391
 
392
static bool FIRCLSDwarfParseAndExecute_register(const void** cursor,
393
                                                DWARFCIERecord* cieRecord,
394
                                                FIRCLSDwarfState* state) {
395
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
396
 
397
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
398
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_register number\n");
399
    return false;
400
  }
401
 
402
  uint64_t regValue = FIRCLSParseULEB128AndAdvance(cursor);
403
 
404
  if (regValue > CLS_DWARF_MAX_REGISTER_NUM) {
405
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_register value\n");
406
    return false;
407
  }
408
 
409
  state->registers[regNum].location = FIRCLSDwarfRegisterInRegister;
410
  state->registers[regNum].value = regValue;
411
 
412
  FIRCLSDwarfLog("DW_CFA_register %llu %llu\n", regNum, regValue);
413
 
414
  return true;
415
}
416
 
417
static bool FIRCLSDwarfParseAndExecute_expression(const void** cursor,
418
                                                  DWARFCIERecord* cieRecord,
419
                                                  FIRCLSDwarfState* state) {
420
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
421
 
422
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
423
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_expression register number\n");
424
    return false;
425
  }
426
 
427
  state->registers[regNum].location = FIRCLSDwarfRegisterAtExpression;
428
  state->registers[regNum].value = (uintptr_t)*cursor;
429
 
430
  // read the length of the expression, and advance past it
431
  uint64_t length = FIRCLSParseULEB128AndAdvance(cursor);
432
  *cursor += length;
433
 
434
  FIRCLSDwarfLog("DW_CFA_expression %llu %llu\n", regNum, length);
435
 
436
  return true;
437
}
438
 
439
static bool FIRCLSDwarfParseAndExecute_val_expression(const void** cursor,
440
                                                      DWARFCIERecord* cieRecord,
441
                                                      FIRCLSDwarfState* state) {
442
  uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor);
443
 
444
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
445
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_val_expression register number\n");
446
    return false;
447
  }
448
 
449
  state->registers[regNum].location = FIRCLSDwarfRegisterIsExpression;
450
  state->registers[regNum].value = (uintptr_t)*cursor;
451
 
452
  // read the length of the expression, and advance past it
453
  uint64_t length = FIRCLSParseULEB128AndAdvance(cursor);
454
  *cursor += length;
455
 
456
  FIRCLSDwarfLog("DW_CFA_val_expression %llu %llu\n", regNum, length);
457
 
458
  return true;
459
}
460
 
461
static bool FIRCLSDwarfParseAndExecute_def_cfa_expression(const void** cursor,
462
                                                          DWARFCIERecord* cieRecord,
463
                                                          FIRCLSDwarfState* state) {
464
  state->cfaRegister = CLS_DWARF_INVALID_REGISTER_NUM;
465
  state->cfaExpression = *cursor;
466
 
467
  // read the length of the expression, and advance past it
468
  uint64_t length = FIRCLSParseULEB128AndAdvance(cursor);
469
  *cursor += length;
470
 
471
  FIRCLSDwarfLog("DW_CFA_def_cfa_expression %llu\n", length);
472
 
473
  return true;
474
}
475
 
476
static bool FIRCLSDwarfParseAndExecute_offset(const void** cursor,
477
                                              DWARFCIERecord* cieRecord,
478
                                              FIRCLSDwarfState* state,
479
                                              uint8_t regNum) {
480
  if (regNum > CLS_DWARF_MAX_REGISTER_NUM) {
481
    FIRCLSSDKLog("Error: Found an invalid DW_CFA_offset register number\n");
482
    return false;
483
  }
484
 
485
  int64_t offset = FIRCLSParseULEB128AndAdvance(cursor) * cieRecord->dataAlignFactor;
486
 
487
  state->registers[regNum].location = FIRCLSDwarfRegisterInCFA;
488
  state->registers[regNum].value = offset;
489
 
490
  FIRCLSDwarfLog("DW_CFA_offset %u, %lld\n", regNum, offset);
491
 
492
  return true;
493
}
494
 
495
static bool FIRCLSDwarfParseAndExecute_advance_loc(const void** cursor,
496
                                                   DWARFCIERecord* cieRecord,
497
                                                   FIRCLSDwarfState* state,
498
                                                   uint8_t delta,
499
                                                   intptr_t* codeOffset) {
500
  if (!FIRCLSIsValidPointer(codeOffset) || !FIRCLSIsValidPointer(cieRecord)) {
501
    FIRCLSSDKLog("Error: invalid inputs\n");
502
    return false;
503
  }
504
 
505
  *codeOffset = delta * (intptr_t)cieRecord->codeAlignFactor;
506
 
507
  FIRCLSDwarfLog("DW_CFA_advance_loc %u\n", delta);
508
 
509
  return true;
510
}
511
 
512
static bool FIRCLSDwarfParseAndExecuteInstructionWithOperand(const void** cursor,
513
                                                             uint8_t instruction,
514
                                                             DWARFCIERecord* cieRecord,
515
                                                             FIRCLSDwarfState* state,
516
                                                             intptr_t* codeOffset) {
517
  uint8_t operand = instruction & DW_CFA_OPERAND_MASK;
518
  bool success = false;
519
 
520
  switch (instruction & DW_CFA_OPCODE_MASK) {
521
    case DW_CFA_offset:
522
      success = FIRCLSDwarfParseAndExecute_offset(cursor, cieRecord, state, operand);
523
      break;
524
    case DW_CFA_advance_loc:
525
      success =
526
          FIRCLSDwarfParseAndExecute_advance_loc(cursor, cieRecord, state, operand, codeOffset);
527
      break;
528
    case DW_CFA_restore:
529
      FIRCLSSDKLog("Error: Unimplemented DWARF instruction with operand 0x%x\n", instruction);
530
      break;
531
    default:
532
      FIRCLSSDKLog("Error: Unrecognized DWARF instruction 0x%x\n", instruction);
533
      break;
534
  }
535
 
536
  return success;
537
}
538
 
539
#pragma mark - Expressions
540
static bool FIRCLSDwarfEvalulateExpression(const void* cursor,
541
                                           const FIRCLSThreadContext* registers,
542
                                           intptr_t stackValue,
543
                                           intptr_t* result) {
544
  FIRCLSDwarfLog("starting at %p with initial value %lx\n", cursor, stackValue);
545
 
546
  if (!FIRCLSIsValidPointer(cursor) || !FIRCLSIsValidPointer(result)) {
547
    FIRCLSSDKLog("Error: inputs invalid\n");
548
    return false;
549
  }
550
 
551
  FIRCLSDwarfExpressionMachine machine;
552
 
553
  if (!FIRCLSDwarfExpressionMachineInit(&machine, cursor, registers, stackValue)) {
554
    FIRCLSSDKLog("Error: unable to init DWARF expression machine\n");
555
    return false;
556
  }
557
 
558
  if (!FIRCLSDwarfExpressionMachinePrepareForExecution(&machine)) {
559
    FIRCLSSDKLog("Error: unable to prepare for execution\n");
560
    return false;
561
  }
562
 
563
  while (!FIRCLSDwarfExpressionMachineIsFinished(&machine)) {
564
    if (!FIRCLSDwarfExpressionMachineExecuteNextOpcode(&machine)) {
565
      FIRCLSSDKLog("Error: failed to execute DWARF machine opcode\n");
566
      return false;
567
    }
568
  }
569
 
570
  if (!FIRCLSDwarfExpressionMachineGetResult(&machine, result)) {
571
    FIRCLSSDKLog("Error: failed to get DWARF expression result\n");
572
    return false;
573
  }
574
 
575
  FIRCLSDwarfLog("successfully computed expression result\n");
576
 
577
  return true;
578
}
579
 
580
#pragma mark - Execution
581
bool FIRCLSDwarfInstructionsEnumerate(DWARFInstructions* instructions,
582
                                      DWARFCIERecord* cieRecord,
583
                                      FIRCLSDwarfState* state,
584
                                      intptr_t pcOffset) {
585
  if (!instructions || !cieRecord || !state) {
586
    FIRCLSSDKLog("Error: inputs invalid\n");
587
    return false;
588
  }
589
 
590
  // This is a little bit of state that can't be put into the state structure, because
591
  // it is possible for instructions to push/pop state that does not affect this value.
592
  intptr_t codeOffset = 0;
593
 
594
  const void* cursor = instructions->data;
595
  const void* endAddress = cursor + instructions->length;
596
 
597
  FIRCLSDwarfLog("Running instructions from %p to %p\n", cursor, endAddress);
598
 
599
  // parse the instructions, as long as:
600
  // - our data pointer is still in range
601
  // - the pc offset is within the range of instructions that apply
602
 
603
  while ((cursor < endAddress) && (codeOffset < pcOffset)) {
604
    uint8_t instruction = FIRCLSParseUint8AndAdvance(&cursor);
605
    bool success = false;
606
 
607
    switch (instruction) {
608
      case DW_CFA_nop:
609
        FIRCLSDwarfLog("DW_CFA_nop\n");
610
        continue;
611
      case DW_CFA_set_loc:
612
        success = FIRCLSDwarfParseAndExecute_set_loc(&cursor, cieRecord, &codeOffset);
613
        break;
614
      case DW_CFA_advance_loc1:
615
        success = FIRCLSDwarfParseAndExecute_advance_loc1(&cursor, cieRecord, &codeOffset);
616
        break;
617
      case DW_CFA_advance_loc2:
618
        success = FIRCLSDwarfParseAndExecute_advance_loc2(&cursor, cieRecord, &codeOffset);
619
        break;
620
      case DW_CFA_advance_loc4:
621
        success = FIRCLSDwarfParseAndExecute_advance_loc4(&cursor, cieRecord, &codeOffset);
622
        break;
623
      case DW_CFA_def_cfa:
624
        success = FIRCLSDwarfParseAndExecute_def_cfa(&cursor, cieRecord, state);
625
        break;
626
      case DW_CFA_def_cfa_register:
627
        success = FIRCLSDwarfParseAndExecute_def_cfa_register(&cursor, cieRecord, state);
628
        break;
629
      case DW_CFA_def_cfa_offset:
630
        success = FIRCLSDwarfParseAndExecute_def_cfa_offset(&cursor, cieRecord, state);
631
        break;
632
      case DW_CFA_same_value:
633
        success = FIRCLSDwarfParseAndExecute_same_value(&cursor, cieRecord, state);
634
        break;
635
      case DW_CFA_register:
636
        success = FIRCLSDwarfParseAndExecute_register(&cursor, cieRecord, state);
637
        break;
638
      case DW_CFA_def_cfa_expression:
639
        success = FIRCLSDwarfParseAndExecute_def_cfa_expression(&cursor, cieRecord, state);
640
        break;
641
      case DW_CFA_expression:
642
        success = FIRCLSDwarfParseAndExecute_expression(&cursor, cieRecord, state);
643
        break;
644
      case DW_CFA_val_expression:
645
        success = FIRCLSDwarfParseAndExecute_val_expression(&cursor, cieRecord, state);
646
        break;
647
      case DW_CFA_offset_extended:
648
      case DW_CFA_restore_extended:
649
      case DW_CFA_undefined:
650
      case DW_CFA_remember_state:
651
      case DW_CFA_restore_state:
652
      case DW_CFA_offset_extended_sf:
653
      case DW_CFA_def_cfa_sf:
654
      case DW_CFA_def_cfa_offset_sf:
655
      case DW_CFA_val_offset:
656
      case DW_CFA_val_offset_sf:
657
      case DW_CFA_GNU_window_save:
658
      case DW_CFA_GNU_args_size:
659
      case DW_CFA_GNU_negative_offset_extended:
660
        FIRCLSSDKLog("Error: Unimplemented DWARF instruction 0x%x\n", instruction);
661
        return false;
662
      default:
663
        success = FIRCLSDwarfParseAndExecuteInstructionWithOperand(&cursor, instruction, cieRecord,
664
                                                                   state, &codeOffset);
665
        break;
666
    }
667
 
668
    if (!success) {
669
      FIRCLSSDKLog("Error: Failed to execute dwarf instruction 0x%x\n", instruction);
670
      return false;
671
    }
672
  }
673
 
674
  return true;
675
}
676
 
677
bool FIRCLSDwarfUnwindComputeRegisters(FIRCLSDwarfCFIRecord* record,
678
                                       FIRCLSThreadContext* registers) {
679
  if (!record || !registers) {
680
    return false;
681
  }
682
 
683
  // We need to run the dwarf instructions to compute our register values.
684
  // - initialize state
685
  // - run the CIE instructions
686
  // - run the FDE instructions
687
  // - grab the values
688
 
689
  FIRCLSDwarfState state;
690
 
691
  memset(&state, 0, sizeof(FIRCLSDwarfState));
692
 
693
  // We need to run all the instructions in the CIE record. So, pass in a large value for the pc
694
  // offset so we don't stop early.
695
  if (!FIRCLSDwarfInstructionsEnumerate(&record->cie.instructions, &record->cie, &state,
696
                                        INTPTR_MAX)) {
697
    FIRCLSSDKLog("Error: Unable to run CIE instructions\n");
698
    return false;
699
  }
700
 
701
  intptr_t pcOffset = FIRCLSThreadContextGetPC(registers) - record->fde.startAddress;
702
  if (pcOffset < 0) {
703
    FIRCLSSDKLog("Error: The FDE pcOffset value cannot be negative\n");
704
    return false;
705
  }
706
 
707
  if (!FIRCLSDwarfInstructionsEnumerate(&record->fde.instructions, &record->cie, &state,
708
                                        pcOffset)) {
709
    FIRCLSSDKLog("Error: Unable to run FDE instructions\n");
710
    return false;
711
  }
712
 
713
  uintptr_t cfaRegister = 0;
714
 
715
  if (!FIRCLSDwarfGetCFA(&state, registers, &cfaRegister)) {
716
    FIRCLSSDKLog("Error: failed to get CFA\n");
717
    return false;
718
  }
719
 
720
  if (!FIRCLSDwarfUnwindAssignRegisters(&state, registers, cfaRegister, registers)) {
721
    FIRCLSSDKLogError("Error: Unable to assign DWARF registers\n");
722
    return false;
723
  }
724
 
725
  return true;
726
}
727
 
728
bool FIRCLSDwarfUnwindAssignRegisters(const FIRCLSDwarfState* state,
729
                                      const FIRCLSThreadContext* registers,
730
                                      uintptr_t cfaRegister,
731
                                      FIRCLSThreadContext* outputRegisters) {
732
  if (!FIRCLSIsValidPointer(state) || !FIRCLSIsValidPointer(registers)) {
733
    FIRCLSSDKLogError("Error: input invalid\n");
734
    return false;
735
  }
736
 
737
  // make a copy, which we'll be changing
738
  FIRCLSThreadContext newThreadState = *registers;
739
 
740
  // loop through all the registers, so we can set their values
741
  for (size_t i = 0; i <= CLS_DWARF_MAX_REGISTER_NUM; ++i) {
742
    if (state->registers[i].location == FIRCLSDwarfRegisterUnused) {
743
      continue;
744
    }
745
 
746
    const uintptr_t value =
747
        FIRCLSDwarfGetSavedRegister(registers, cfaRegister, state->registers[i]);
748
 
749
    if (!FIRCLSDwarfUnwindSetRegisterValue(&newThreadState, i, value)) {
750
      FIRCLSSDKLog("Error: Unable to restore register value\n");
751
      return false;
752
    }
753
  }
754
 
755
  if (!FIRCLSDwarfUnwindSetRegisterValue(&newThreadState, CLS_DWARF_REG_SP, cfaRegister)) {
756
    FIRCLSSDKLog("Error: Unable to restore SP value\n");
757
    return false;
758
  }
759
 
760
  // sanity-check that things have changed
761
  if (FIRCLSDwarfCompareRegisters(registers, &newThreadState, CLS_DWARF_REG_SP)) {
762
    FIRCLSSDKLog("Error: Stack pointer hasn't changed\n");
763
    return false;
764
  }
765
 
766
  if (FIRCLSDwarfCompareRegisters(registers, &newThreadState, CLS_DWARF_REG_RETURN)) {
767
    FIRCLSSDKLog("Error: PC hasn't changed\n");
768
    return false;
769
  }
770
 
771
  // set our new value
772
  *outputRegisters = newThreadState;
773
 
774
  return true;
775
}
776
 
777
#pragma mark - Register Operations
778
bool FIRCLSDwarfCompareRegisters(const FIRCLSThreadContext* a,
779
                                 const FIRCLSThreadContext* b,
780
                                 uint64_t registerNum) {
781
  return FIRCLSDwarfUnwindGetRegisterValue(a, registerNum) ==
782
         FIRCLSDwarfUnwindGetRegisterValue(b, registerNum);
783
}
784
 
785
bool FIRCLSDwarfGetCFA(FIRCLSDwarfState* state,
786
                       const FIRCLSThreadContext* registers,
787
                       uintptr_t* cfa) {
788
  if (!FIRCLSIsValidPointer(state) || !FIRCLSIsValidPointer(registers) ||
789
      !FIRCLSIsValidPointer(cfa)) {
790
    FIRCLSSDKLog("Error: invalid input\n");
791
    return false;
792
  }
793
 
794
  if (state->cfaExpression) {
795
    if (!FIRCLSDwarfEvalulateExpression(state->cfaExpression, registers, 0, (intptr_t*)cfa)) {
796
      FIRCLSSDKLog("Error: failed to compute CFA expression\n");
797
      return false;
798
    }
799
 
800
    return true;
801
  }
802
 
803
  // libunwind checks that cfaRegister is not zero. This seems like a potential bug - why couldn't
804
  // it be zero?
805
 
806
  *cfa = FIRCLSDwarfUnwindGetRegisterValue(registers, state->cfaRegister) +
807
         (uintptr_t)state->cfaRegisterOffset;
808
 
809
  return true;
810
}
811
 
812
uintptr_t FIRCLSDwarfGetSavedRegister(const FIRCLSThreadContext* registers,
813
                                      uintptr_t cfaRegister,
814
                                      FIRCLSDwarfRegister dRegister) {
815
  intptr_t result = 0;
816
 
817
  FIRCLSDwarfLog("Getting register %x\n", dRegister.location);
818
 
819
  switch (dRegister.location) {
820
    case FIRCLSDwarfRegisterInCFA: {
821
      const uintptr_t address = cfaRegister + (uintptr_t)dRegister.value;
822
 
823
      if (!FIRCLSReadMemory(address, &result, sizeof(result))) {
824
        FIRCLSSDKLog("Error: Unable to read CFA value\n");
825
        return 0;
826
      }
827
    }
828
      return result;
829
    case FIRCLSDwarfRegisterInRegister:
830
      return FIRCLSDwarfUnwindGetRegisterValue(registers, dRegister.value);
831
    case FIRCLSDwarfRegisterOffsetFromCFA:
832
      FIRCLSSDKLog("Error: OffsetFromCFA unhandled\n");
833
      break;
834
    case FIRCLSDwarfRegisterAtExpression:
835
      if (!FIRCLSDwarfEvalulateExpression((void*)dRegister.value, registers, cfaRegister,
836
                                          &result)) {
837
        FIRCLSSDKLog("Error: unable to evaluate expression\n");
838
        return 0;
839
      }
840
 
841
      if (!FIRCLSReadMemory(result, &result, sizeof(result))) {
842
        FIRCLSSDKLog("Error: Unable to read memory computed from expression\n");
843
        return 0;
844
      }
845
 
846
      return result;
847
    case FIRCLSDwarfRegisterIsExpression:
848
      if (!FIRCLSDwarfEvalulateExpression((void*)dRegister.value, registers, cfaRegister,
849
                                          &result)) {
850
        FIRCLSSDKLog("Error: unable to evaluate expression\n");
851
        return 0;
852
      }
853
 
854
      return result;
855
    default:
856
      FIRCLSSDKLog("Error: Unrecognized register save location 0x%x\n", dRegister.location);
857
      break;
858
  }
859
 
860
  return 0;
861
}
862
 
863
#if DEBUG
864
#pragma mark - Debugging
865
void FIRCLSCFIRecordShow(FIRCLSDwarfCFIRecord* record) {
866
  if (!record) {
867
    FIRCLSSDKLog("Error: CFI record: null\n");
868
    return;
869
  }
870
 
871
  FIRCLSCIERecordShow(&record->cie);
872
  FIRCLSFDERecordShow(&record->fde, &record->cie);
873
}
874
 
875
void FIRCLSCIERecordShow(DWARFCIERecord* record) {
876
  if (!record) {
877
    FIRCLSSDKLog("Error: CIE: null\n");
878
    return;
879
  }
880
 
881
  FIRCLSSDKLog("CIE:\n");
882
  FIRCLSSDKLog("       length: %llu\n", record->length);
883
  FIRCLSSDKLog("      version: %u\n", record->version);
884
  FIRCLSSDKLog(" augmentation: %s\n", record->augmentation);
885
  FIRCLSSDKLog("      EH Data: 0x%04lx\n", record->ehData);
886
  FIRCLSSDKLog("LSDA encoding: 0x%02x\n", record->lsdaEncoding);
887
  FIRCLSSDKLog("  personality: 0x%lx\n", record->personalityFunction);
888
 
889
  FIRCLSDwarfPointerEncodingShow("     encoding", record->pointerEncoding);
890
  FIRCLSDwarfPointerEncodingShow("   P encoding", record->personalityEncoding);
891
 
892
  FIRCLSSDKLog("   code align: %llu\n", record->codeAlignFactor);
893
  FIRCLSSDKLog("   data align: %lld\n", record->dataAlignFactor);
894
  FIRCLSSDKLog("  RA register: %llu\n", record->returnAddressRegister);
895
 
896
  FIRCLSDwarfInstructionsShow(&record->instructions, record);
897
}
898
 
899
void FIRCLSFDERecordShow(DWARFFDERecord* record, DWARFCIERecord* cie) {
900
  if (!record) {
901
    FIRCLSSDKLog("FDE: null\n");
902
    return;
903
  }
904
 
905
  FIRCLSSDKLog("FDE:\n");
906
  FIRCLSSDKLog("      length: %llu\n", record->length);
907
  FIRCLSSDKLog("  CIE offset: %llu\n", record->cieOffset);
908
  FIRCLSSDKLog("  start addr: 0x%lx\n", record->startAddress);
909
  FIRCLSSDKLog("       range: %lu\n", record->rangeSize);
910
 
911
  FIRCLSDwarfInstructionsShow(&record->instructions, cie);
912
}
913
 
914
void FIRCLSDwarfPointerEncodingShow(const char* leadString, uint8_t encoding) {
915
  if (encoding == DW_EH_PE_omit) {
916
    FIRCLSSDKLog("%s: 0x%02x (omit)\n", leadString, encoding);
917
  } else {
918
    const char* peValue = "";
919
    const char* peOffset = "";
920
 
921
    switch (encoding & DW_EH_PE_VALUE_MASK) {
922
      case DW_EH_PE_absptr:
923
        peValue = "DW_EH_PE_absptr";
924
        break;
925
      case DW_EH_PE_uleb128:
926
        peValue = "DW_EH_PE_uleb128";
927
        break;
928
      case DW_EH_PE_udata2:
929
        peValue = "DW_EH_PE_udata2";
930
        break;
931
      case DW_EH_PE_udata4:
932
        peValue = "DW_EH_PE_udata4";
933
        break;
934
      case DW_EH_PE_udata8:
935
        peValue = "DW_EH_PE_udata8";
936
        break;
937
      case DW_EH_PE_signed:
938
        peValue = "DW_EH_PE_signed";
939
        break;
940
      case DW_EH_PE_sleb128:
941
        peValue = "DW_EH_PE_sleb128";
942
        break;
943
      case DW_EH_PE_sdata2:
944
        peValue = "DW_EH_PE_sdata2";
945
        break;
946
      case DW_EH_PE_sdata4:
947
        peValue = "DW_EH_PE_sdata4";
948
        break;
949
      case DW_EH_PE_sdata8:
950
        peValue = "DW_EH_PE_sdata8";
951
        break;
952
      default:
953
        peValue = "unknown";
954
        break;
955
    }
956
 
957
    switch (encoding & DW_EH_PE_RELATIVE_OFFSET_MASK) {
958
      case DW_EH_PE_absptr:
959
        break;
960
      case DW_EH_PE_pcrel:
961
        peOffset = " + DW_EH_PE_pcrel";
962
        break;
963
      case DW_EH_PE_textrel:
964
        peOffset = " + DW_EH_PE_textrel";
965
        break;
966
      case DW_EH_PE_datarel:
967
        peOffset = " + DW_EH_PE_datarel";
968
        break;
969
      case DW_EH_PE_funcrel:
970
        peOffset = " + DW_EH_PE_funcrel";
971
        break;
972
      case DW_EH_PE_aligned:
973
        peOffset = " + DW_EH_PE_aligned";
974
        break;
975
      case DW_EH_PE_indirect:
976
        peOffset = " + DW_EH_PE_indirect";
977
        break;
978
      default:
979
        break;
980
    }
981
 
982
    FIRCLSSDKLog("%s: 0x%02x (%s%s)\n", leadString, encoding, peValue, peOffset);
983
  }
984
}
985
 
986
void FIRCLSDwarfInstructionsShow(DWARFInstructions* instructions, DWARFCIERecord* cie) {
987
  if (!instructions) {
988
    FIRCLSSDKLog("Error: Instructions null\n");
989
  }
990
 
991
  FIRCLSDwarfState state;
992
 
993
  memset(&state, 0, sizeof(FIRCLSDwarfState));
994
 
995
  FIRCLSDwarfInstructionsEnumerate(instructions, cie, &state, -1);
996
}
997
 
998
#endif
999
 
1000
#else
1001
INJECT_STRIP_SYMBOL(dwarf_unwind)
1002
#endif