forked from dechaoqiu/atosl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
macho.c
3334 lines (2989 loc) · 117 KB
/
macho.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* =====================================================================================
*
* Filename: macho.c
*
* Description: Mach-O Reader
*
* Version: 1.0
* Created: 02/17/2013 22:51:27
* Revision: none
* Compiler: gcc
*
* Author: Reno Qiu
* Organization:
*
* =====================================================================================
*/
#include "macho.h"
char *project_name;
static struct die_info * read_die_and_children (char *info_ptr, struct dwarf2_cu *cu, char **new_info_ptr, struct die_info *parent);
static struct die_info * read_die_and_siblings (char *info_ptr, struct dwarf2_cu *cu, char **new_info_ptr, struct die_info *parent);
/* Free the line_header structure *LH, and any arrays and strings it
refers to. */
static void free_line_header (struct line_header *lh)
{
if (lh->standard_opcode_lengths)
free (lh->standard_opcode_lengths);
/* Remember that all the lh->file_names[i].name pointers are
pointers into debug_line_buffer, and don't need to be freed. */
if (lh->file_names)
free (lh->file_names);
/* Similarly for the include directory names. */
if (lh->include_dirs)
free (lh->include_dirs);
free (lh);
}
static CORE_ADDR read_signed_16(char *info_ptr){
signed int ret = 0;
ret = info_ptr[1];
ret = (ret << 8) + info_ptr[0];
return ret;
}
static signed int read_signed_32(char *info_ptr){
unsigned char * temp_ptr = (unsigned char *)info_ptr;
signed int ret = 0;
ret = temp_ptr[3];
ret = (ret << 8) + temp_ptr[2];
ret = (ret << 8) + temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static int64_t read_signed_64(char *info_ptr){
unsigned char * temp_ptr = (unsigned char *)info_ptr;
int64_t ret = 0;
ret = temp_ptr[7];
ret = (ret << 8) + temp_ptr[6];
ret = (ret << 8) + temp_ptr[5];
ret = (ret << 8) + temp_ptr[4];
ret = (ret << 8) + temp_ptr[3];
ret = (ret << 8) + temp_ptr[2];
ret = (ret << 8) + temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned int read_1_byte (char *info_ptr)
{
unsigned char * temp_ptr = (unsigned char *)info_ptr;
return *temp_ptr;
}
static int read_1_signed_byte (char *buf)
{
int ret = 0;
ret = (int)*buf;
return ret;
}
static unsigned int read_2_bytes (char *info_ptr)
{
//read bytes little endian?
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned short ret = 0;
ret = temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned int read_4_bytes(char *info_ptr)
{
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned int ret = 0;
ret = temp_ptr[3];
ret = (ret << 8) + temp_ptr[2];
ret = (ret << 8) + temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned long read_8_bytes (char *info_ptr)
{
//read bytes little endian?
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned long ret = 0;
ret = temp_ptr[7];
ret = (ret << 8) + temp_ptr[6];
ret = (ret << 8) + temp_ptr[5];
ret = (ret << 8) + temp_ptr[4];
ret = (ret << 8) + temp_ptr[3];
ret = (ret << 8) + temp_ptr[2];
ret = (ret << 8) + temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned int read_unsigned_int(char *info_ptr){
//read bytes little endian?
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned int ret = 0;
ret = temp_ptr[3];
ret = (ret << 8) + temp_ptr[2];
ret = (ret << 8) + temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned short read_unsigned_short(char *info_ptr){
//read bytes little endian?
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned short ret = 0;
ret = temp_ptr[1];
ret = (ret << 8) + temp_ptr[0];
return ret;
}
static unsigned char read_unsigned_char(char *info_ptr){
unsigned char * temp_ptr = (unsigned char *)info_ptr;
unsigned char ret = 0;
ret = temp_ptr[0];
return ret;
}
static long long read_signed_leb128(char* leb128_str, unsigned int* leb128_length)
{
unsigned char * leb128 = (unsigned char * )leb128_str;
signed long long number = 0;
int sign = 0;
signed long shift = 0;
unsigned char byte = *leb128;
signed long byte_length = 1;
/* byte_length being the number of bytes of data absorbed so far in
* turning the leb into a Dwarf_Signed. */
for (;;) {
sign = byte & 0x40;
number |= ((signed long long) ((byte & 0x7f))) << shift;
shift += 7;
if ((byte & 0x80) == 0) {
break;
}
++leb128;
byte = *leb128;
byte_length++;
}
if ((shift < sizeof(signed long long) * 8) && sign) {
number |= -((signed long long) 1 << shift);
}
if (leb128_length != NULL)
*leb128_length = byte_length;
return (number);
}
static unsigned long long read_unsigned_leb128(char* leb128_str, unsigned int* leb128_length)
{
unsigned char byte;
unsigned long word_number;
unsigned long long number;
signed long shift;
signed long byte_length;
unsigned char * leb128 = (unsigned char * )leb128_str;
/* The following unrolls-the-loop for the first few bytes and
* unpacks into 32 bits to make this as fast as possible.
* word_number is assumed big enough that the shift has a defined
* result. */
if ((*leb128 & 0x80) == 0) {
if (leb128_length != NULL)
*leb128_length = 1;
return (*leb128);
} else if ((*(leb128 + 1) & 0x80) == 0) {
if (leb128_length != NULL)
*leb128_length = 2;
word_number = *leb128 & 0x7f;
word_number |= (*(leb128 + 1) & 0x7f) << 7;
return (word_number);
} else if ((*(leb128 + 2) & 0x80) == 0) {
if (leb128_length != NULL)
*leb128_length = 3;
word_number = *leb128 & 0x7f;
word_number |= (*(leb128 + 1) & 0x7f) << 7;
word_number |= (*(leb128 + 2) & 0x7f) << 14;
return (word_number);
} else if ((*(leb128 + 3) & 0x80) == 0) {
if (leb128_length != NULL)
*leb128_length = 4;
word_number = *leb128 & 0x7f;
word_number |= (*(leb128 + 1) & 0x7f) << 7;
word_number |= (*(leb128 + 2) & 0x7f) << 14;
word_number |= (*(leb128 + 3) & 0x7f) << 21;
return (word_number);
}
/* The rest handles long numbers Because the 'number' may be larger
* than the default int/unsigned, we must cast the 'byte' before
* the shift for the shift to have a defined result. */
number = 0;
shift = 0;
byte_length = 1;
byte = *(leb128);
for (;;) {
number |= ((unsigned int) (byte & 0x7f)) << shift;
if ((byte & 0x80) == 0) {
if (leb128_length != NULL)
*leb128_length = byte_length;
return (number);
}
shift += 7;
byte_length++;
++leb128;
byte = *leb128;
}
}
static char * read_string (char *buf, unsigned int *bytes_read_ptr)
{
if (*buf == '\0')
{
*bytes_read_ptr = 1;
return NULL;
}
*bytes_read_ptr = strlen (buf) + 1;
return buf;
}
/* Read an offset from the data stream. The size of the offset is
given by cu_header->offset_size. */
static long read_offset (char *buf, const struct comp_unit_head *cu_header, int *bytes_read)
{
long retval = 0;
switch (cu_header->offset_size)
{
case 4:
retval = read_4_bytes(buf);
*bytes_read = 4;
break;
case 8:
retval = read_8_bytes(buf);
*bytes_read = 8;
break;
default:
printf("read_offset: bad switch\n");
}
return retval;
}
static CORE_ADDR read_address_of_cu (char *buf, struct dwarf2_cu *cu, int *bytes_read)
{
struct comp_unit_head *cu_header = &cu->header;
CORE_ADDR retval = 0;
switch (cu_header->addr_size)
{
case 2:
//unsigned
retval = read_signed_16(buf);
break;
case 4:
retval = read_signed_32(buf);
break;
case 8:
retval = read_signed_64(buf);
break;
default:
printf("read address: bad switch, signed\n");
}
*bytes_read = cu_header->addr_size;
return retval;
}
/* Read the initial length from a section. The (draft) DWARF 3
specification allows the initial length to take up either 4 bytes
or 12 bytes. If the first 4 bytes are 0xffffffff, then the next 8
bytes describe the length and all offsets will be 8 bytes in length
instead of 4.
An older, non-standard 64-bit format is also handled by this
function. The older format in question stores the initial length
as an 8-byte quantity without an escape value. Lengths greater
than 2^32 aren't very common which means that the initial 4 bytes
is almost always zero. Since a length value of zero doesn't make
sense for the 32-bit format, this initial zero can be considered to
be an escape value which indicates the presence of the older 64-bit
format. As written, the code can't detect (old format) lengths
greater than 4GB. If it becomes necessary to handle lengths
somewhat larger than 4GB, we could allow other small values (such
as the non-sensical values of 1, 2, and 3) to also be used as
escape values indicating the presence of the old format.
The value returned via bytes_read should be used to increment the
relevant pointer after calling read_initial_length_of_comp_unit().
As a side effect, this function sets the fields initial_length_size
and offset_size in cu_header to the values appropriate for the
length field. (The format of the initial length field determines
the width of file offsets to be fetched later with read_offset().)
[ Note: read_initial_length_of_comp_unit() and read_offset() are based on the
document entitled "DWARF Debugging Information Format", revision
3, draft 8, dated November 19, 2001. This document was obtained
from:
http://reality.sgiweb.org/davea/dwarf3-draft8-011125.pdf
This document is only a draft and is subject to change. (So beware.)
Details regarding the older, non-standard 64-bit format were
determined empirically by examining 64-bit ELF files produced by
the SGI toolchain on an IRIX 6.5 machine.
- Kevin, July 16, 2002
] */
static long read_initial_length_of_aranges(char *buf, struct aranges_header *aranges_header, int *bytes_read){
long length = read_4_bytes(buf);
return length;
}
static long read_initial_length_of_comp_unit (char *buf, struct comp_unit_head *cu_header,
int *bytes_read)
{
long length = read_4_bytes(buf);
if (length == 0xffffffff)
{
length = read_8_bytes(buf + 4);
*bytes_read = 12;
}
else if (length == 0)
{
/* Handle the (non-standard) 63-bit DWARF2 format used by IRIX. */
length = read_8_bytes(buf + 4);
*bytes_read = 8;
}
else
{
*bytes_read = 4;
}
if (cu_header)
{
assert (cu_header->initial_length_size == 0
|| cu_header->initial_length_size == 4
|| cu_header->initial_length_size == 8
|| cu_header->initial_length_size == 12);
if(cu_header->initial_length_size != 0
&& cu_header->initial_length_size != 4
&& cu_header->initial_length_size != 8
&& cu_header->initial_length_size != 12){
PyErr_Format(ATOSLError, "cu_header->initial_length_size invalid");
return -1;
}
if (cu_header->initial_length_size != 0 && cu_header->initial_length_size != *bytes_read){
PyErr_Format(ATOSLError, "cu_header->initial_length_size is not equal to bytes_read");
fprintf(stderr, "cu_header->initial_length_size is not equal to bytes_read\n");
return -1;
}
cu_header->initial_length_size = *bytes_read;
cu_header->offset_size = (*bytes_read == 4) ? 4 : 8;
}
return length;
}
/* Add an entry to LH's include directory table. */
static void add_include_dir (struct line_header *lh, char *include_dir)
{
/* Grow the array if necessary. */
if (lh->include_dirs_size == 0)
{
lh->include_dirs_size = 1; /* for testing */
lh->include_dirs = malloc (lh->include_dirs_size * sizeof (*lh->include_dirs));
}
else if (lh->num_include_dirs >= lh->include_dirs_size)
{
lh->include_dirs_size *= 2;
lh->include_dirs = realloc (lh->include_dirs, (lh->include_dirs_size * sizeof (*lh->include_dirs)));
}
lh->include_dirs[lh->num_include_dirs++] = include_dir;
}
/* Add an entry to LH's file name table. */
static void add_file_name (struct line_header *lh,
char *name,
unsigned int dir_index,
unsigned int mod_time,
unsigned int length)
{
struct file_entry *fe;
/* Grow the array if necessary. */
if (lh->file_names_size == 0)
{
lh->file_names_size = 1; /* for testing */
lh->file_names = malloc (lh->file_names_size
* sizeof (*lh->file_names));
}
else if (lh->num_file_names >= lh->file_names_size)
{
lh->file_names_size *= 2;
lh->file_names = realloc (lh->file_names,
(lh->file_names_size
* sizeof (*lh->file_names)));
}
fe = &lh->file_names[lh->num_file_names++];
fe->name = name;
fe->dir_index = dir_index;
fe->mod_time = mod_time;
fe->length = length;
fe->included_p = 0;
}
/* Read the statement program header starting at OFFSET in
.debug_line, according to the endianness of ABFD. Return a pointer
to a struct line_header, allocated using xmalloc.
NOTE: the strings in the include directory and file name tables of
the returned object point into debug_line_buffer, and must not be
freed. */
static struct line_header * dwarf_decode_line_header (unsigned int offset, struct dwarf2_cu *cu)
{
struct dwarf2_per_objfile *dwarf2_per_objfile = cu->dwarf2_per_objfile;
// struct cleanup *back_to;
struct line_header *lh;
char *line_ptr;
/* APPLE LOCAL avoid type warnings by making BYTES_READ unsigned. */
unsigned bytes_read;
int i;
char *cur_dir, *cur_file;
if (dwarf2_per_objfile->line_buffer == NULL)
{
printf("missing .debug_line section\n");
PyErr_Format(ATOSLError, "missing .debug_line section");
return NULL;
}
/* Make sure that at least there's room for the total_length field.
That could be 12 bytes long, but we're just going to fudge that. */
if (offset + 4 >= dwarf2_per_objfile->line_size)
{
//dwarf2_statement_list_fits_in_line_number_section_complaint ();
printf(".debug_line incomplete.\n");
PyErr_Format(ATOSLError, ".debug_line incomplete");
return NULL;
}
lh = malloc (sizeof (*lh));
memset (lh, 0, sizeof (*lh));
//back_to = make_cleanup ((make_cleanup_ftype *) free_line_header, (void *) lh);
line_ptr = dwarf2_per_objfile->line_buffer + offset;
/* Read in the header. */
/* APPLE LOCAL Add cast to avoid type mismatch in arg4 warning. */
lh->total_length = read_initial_length_of_comp_unit (line_ptr, &cu->header, (int *) &bytes_read);
if(lh->total_length == -1){
return NULL;
}
line_ptr += bytes_read;
if (line_ptr + lh->total_length > (dwarf2_per_objfile->line_buffer
+ dwarf2_per_objfile->line_size))
{
printf(".debug_line incomplete.\n");
PyErr_Format(ATOSLError, ".debug_line incomplete");
return NULL;
}
lh->statement_program_end = line_ptr + lh->total_length;
lh->version = read_2_bytes (line_ptr);
line_ptr += 2;
/* APPLE LOCAL Add cast to avoid type mismatch in arg4 warning. */
lh->header_length = read_offset (line_ptr, &cu->header, (int *) &bytes_read);
line_ptr += bytes_read;
lh->minimum_instruction_length = read_1_byte (line_ptr);
line_ptr += 1;
lh->default_is_stmt = read_1_byte (line_ptr);
line_ptr += 1;
lh->line_base = read_1_signed_byte (line_ptr);
line_ptr += 1;
lh->line_range = read_1_byte (line_ptr);
line_ptr += 1;
lh->opcode_base = read_1_byte (line_ptr);
line_ptr += 1;
lh->standard_opcode_lengths = (unsigned char *) malloc (lh->opcode_base * sizeof (unsigned char));
lh->standard_opcode_lengths[0] = 1; /* This should never be used anyway. */
for (i = 1; i < lh->opcode_base; ++i)
{
lh->standard_opcode_lengths[i] = read_1_byte (line_ptr);
line_ptr += 1;
}
/* Read directory table. */
while ((cur_dir = read_string (line_ptr, &bytes_read)) != NULL)
{
line_ptr += bytes_read;
add_include_dir (lh, cur_dir);
}
line_ptr += bytes_read;
/* Read file name table. */
while ((cur_file = read_string (line_ptr, &bytes_read)) != NULL)
{
unsigned int dir_index, mod_time, length;
line_ptr += bytes_read;
dir_index = read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time = read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
length = read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
add_file_name (lh, cur_file, dir_index, mod_time, length);
}
line_ptr += bytes_read;
lh->statement_program_start = line_ptr;
if (line_ptr > (dwarf2_per_objfile->line_buffer + dwarf2_per_objfile->line_size)){
printf("line number info header doesn't fit in `.debug_line' section\n");
PyErr_Format(ATOSLError, "line number info header doesn't fit in `.debug_line' section");
return NULL;
}
// discard_cleanups (back_to);
return lh;
}
/* Add a linetable entry for line number LINE and address PC to the
line vector for SUBFILE. */
static void record_line (struct subfile *subfile, int line, CORE_ADDR pc)
{
struct linetable_entry *e;
/* Ignore the dummy line number in libg.o */
if (line == 0xffff)
{
return;
}
/* Make sure line vector exists and is big enough. */
if (!subfile->line_vector)
{
subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH;
subfile->line_vector = (struct linetable *) malloc (sizeof (struct linetable) + subfile->line_vector_length * sizeof (struct linetable_entry));
subfile->line_vector->nitems = 0;
/* APPLE LOCAL codewarrior support */
subfile->line_vector->lines_are_chars = 0;
//have_line_numbers = 1;
}
if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length)
{
subfile->line_vector_length *= 2;
subfile->line_vector = (struct linetable *) realloc ((char *) subfile->line_vector,
(sizeof (struct linetable)
+ (subfile->line_vector_length
* sizeof (struct linetable_entry))));
}
e = subfile->line_vector->item + subfile->line_vector->nitems++;
e->line = line;
e->pc = pc;
// e->pc = ADDR_BITS_REMOVE(pc);
}
/* Needed in order to sort line tables from IBM xcoff files. Sigh! */
/* APPLE LOCAL make compare_line_numbers extern */
//static int compare_line_numbers (const void *ln1p, const void *ln2p)
//{
// struct linetable_entry *ln1 = (struct linetable_entry *) ln1p;
// struct linetable_entry *ln2 = (struct linetable_entry *) ln2p;
//
// /* Note: this code does not assume that CORE_ADDRs can fit in ints.
// Please keep it that way. */
// if (ln1->pc < ln2->pc)
// return -1;
//
// if (ln1->pc > ln2->pc)
// return 1;
//
// /* If pc equal, sort by line. I'm not sure whether this is optimum
// behavior (see comment at struct linetable in symtab.h). */
// return ln1->line - ln2->line;
//}
/* Decode the Line Number Program (LNP) for the given line_header
structure and CU. The actual information extracted and the type
of structures created from the LNP depends on the value of PST.
1. If PST is NULL, then this procedure uses the data from the program
to create all necessary symbol tables, and their linetables.
The compilation directory of the file is passed in COMP_DIR,
and must not be NULL.
2. If PST is not NULL, this procedure reads the program to determine
the list of files included by the unit represented by PST, and
builds all the associated partial symbol tables. In this case,
the value of COMP_DIR is ignored, and can thus be NULL (the COMP_DIR
is not used to compute the full name of the symtab, and therefore
omitting it when building the partial symtab does not introduce
the potential for inconsistency - a partial symtab and its associated
symbtab having a different fullname -). */
static struct subfile * dwarf_decode_lines (struct line_header *lh, char *comp_dir, struct dwarf2_cu *cu)
{
char *line_ptr;
char *line_end;
unsigned int bytes_read;
unsigned char op_code, extended_op, adj_opcode;
CORE_ADDR baseaddr;
//struct objfile *objfile = cu->objfile;
// const int decode_for_pst_p = (pst != NULL);
const int decode_for_pst_p = 0;
/* APPLE LOCAL: We'll need to skip linetable entries in functions that
were coalesced out. */
int record_linetable_entry = 1;
struct subfile *current_subfile = malloc (sizeof (struct subfile));
memset(current_subfile, 0, sizeof(struct subfile));
/* APPLE LOCAL */
//if (debug_debugmap)
// fprintf_unfiltered (gdb_stdlog,
// "debugmap: reading line program for %s\n",
// cu->per_cu->psymtab->filename);
//baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
baseaddr = 0;
line_ptr = lh->statement_program_start;
line_end = lh->statement_program_end;
/* Read the statement sequences until there's nothing left. */
while (line_ptr < line_end)
{
/* state machine registers */
CORE_ADDR address = 0;
unsigned int file = 1;
unsigned int line = 1;
//unsigned int column = 0;
int is_stmt = lh->default_is_stmt;
//int basic_block = 0;
int end_sequence = 0;
//if (!decode_for_pst_p && lh->num_file_names >= file)
//{
// /* Start a subfile for the current file of the state machine. */
// /* lh->include_dirs and lh->file_names are 0-based, but the
// directory and file name numbers in the statement program
// are 1-based. */
// struct file_entry *fe = &lh->file_names[file - 1];
// char *dir;
// if (fe->dir_index)
// dir = lh->include_dirs[fe->dir_index - 1];
// else
// dir = comp_dir;
// /* APPLE LOCAL: Pass in the compilation directory of this CU. */
// dwarf2_start_subfile (fe->name, dir, cu->comp_dir);
//}
/* Decode the table. */
while (!end_sequence)
{
op_code = read_1_byte (line_ptr);
line_ptr += 1;
if (op_code >= lh->opcode_base)
{
/* Special operand. */
adj_opcode = op_code - lh->opcode_base;
address += (adj_opcode / lh->line_range)
* lh->minimum_instruction_length;
line += lh->line_base + (adj_opcode % lh->line_range);
lh->file_names[file - 1].included_p = 1;
/* APPLE LOCAL: Skip linetable entries coalesced out */
if (!decode_for_pst_p && record_linetable_entry)
{
/* Append row to matrix using current values. */
//FIXME check_cu_functions
//record_line (current_subfile, line, check_cu_functions (address, cu));
record_line (current_subfile, line, address);
}
//basic_block = 1;
}
else switch (op_code)
{
case DW_LNS_extended_op:
read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
extended_op = read_1_byte (line_ptr);
line_ptr += 1;
switch (extended_op)
{
case DW_LNE_end_sequence:
end_sequence = 1;
lh->file_names[file - 1].included_p = 1;
/* APPLE LOCAL: Skip linetable entries coalesced out */
if (!decode_for_pst_p && record_linetable_entry){
//record_line (current_subfile, 0, address);
record_line (current_subfile, line, address);
}
break;
case DW_LNE_set_address:
/* APPLE LOCAL Add cast to avoid type mismatch in arg4 warn.*/
address = read_address_of_cu (line_ptr, cu, (int *) &bytes_read);
/* APPLE LOCAL: debug map */
{
//CORE_ADDR addr;
//FIXME
//if (translate_debug_map_address (cu, address, &addr, 0))
//{
// address = addr;
// record_linetable_entry = 1;
//}
//else
record_linetable_entry = 1;
}
line_ptr += bytes_read;
address += baseaddr;
break;
case DW_LNE_define_file:
{
char *cur_file;
unsigned int dir_index, mod_time, length;
cur_file = read_string (line_ptr, &bytes_read);
line_ptr += bytes_read;
dir_index =
read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
mod_time =
read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
length =
read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
add_file_name (lh, cur_file, dir_index, mod_time, length);
}
break;
default:
printf("mangled .debug_line section\n");
return NULL;
}
break;
case DW_LNS_copy:
lh->file_names[file - 1].included_p = 1;
/* APPLE LOCAL: Skip linetable entries coalesced out */
if (!decode_for_pst_p && record_linetable_entry)
// record_line (current_subfile, line, check_cu_functions (address, cu));
record_line (current_subfile, line, address);
//basic_block = 0;
break;
case DW_LNS_advance_pc:
address += lh->minimum_instruction_length
* read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
case DW_LNS_advance_line:
line += read_signed_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
case DW_LNS_set_file:
{
/* The arrays lh->include_dirs and lh->file_names are
0-based, but the directory and file name numbers in
the statement program are 1-based. */
file = read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
//struct file_entry *fe;
//fe = &lh->file_names[file - 1];
//char *dir = NULL;
//if (fe->dir_index)
// dir = lh->include_dirs[fe->dir_index - 1];
//else
// dir = comp_dir;
/* APPLE LOCAL: Pass in the compilation dir of this CU. */
//FIXME
//if (!decode_for_pst_p)
// dwarf2_start_subfile (fe->name, dir, cu->comp_dir);
}
break;
case DW_LNS_set_column:
//column = read_unsigned_leb128 (line_ptr, &bytes_read);
read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
break;
case DW_LNS_negate_stmt:
is_stmt = (!is_stmt);
break;
case DW_LNS_set_basic_block:
//basic_block = 1;
break;
/* Add to the address register of the state machine the
address increment value corresponding to special opcode
255. I.e., this value is scaled by the minimum
instruction length since special opcode 255 would have
scaled the the increment. */
case DW_LNS_const_add_pc:
address += (lh->minimum_instruction_length
* ((255 - lh->opcode_base) / lh->line_range));
break;
case DW_LNS_fixed_advance_pc:
address += read_2_bytes (line_ptr);
line_ptr += 2;
break;
default:
{
/* Unknown standard opcode, ignore it. */
int i;
for (i = 0; i < lh->standard_opcode_lengths[op_code]; i++)
{
(void) read_unsigned_leb128 (line_ptr, &bytes_read);
line_ptr += bytes_read;
}
}
}
}
}
return current_subfile;
}
//static void set_cu_language (unsigned int lang, struct dwarf2_cu *cu)
//{
// switch (lang)
// {
// case DW_LANG_C89:
// case DW_LANG_C:
// cu->language = language_c;
// break;
// case DW_LANG_C_plus_plus:
// cu->language = language_cplus;
// break;
// case DW_LANG_Fortran77:
// case DW_LANG_Fortran90:
// case DW_LANG_Fortran95:
// cu->language = language_fortran;
// break;
// case DW_LANG_Mips_Assembler:
// cu->language = language_asm;
// break;
// case DW_LANG_Java:
// cu->language = language_java;
// break;
// case DW_LANG_Ada83:
// case DW_LANG_Ada95:
// cu->language = language_ada;
// break;
// /* APPLE LOCAL: No need to be Apple local but not merged in to FSF.. */
// case DW_LANG_ObjC:
// cu->language = language_objc;
// break;
// /* APPLE LOCAL: No need to be Apple local but not merged in to FSF.. */
// case DW_LANG_ObjC_plus_plus:
// cu->language = language_objcplus;
// break;
// case DW_LANG_Cobol74:
// case DW_LANG_Cobol85:
// case DW_LANG_Pascal83:
// case DW_LANG_Modula2:
// default:
// cu->language = language_minimal;
// break;
// }
// //cu->language_defn = language_def (cu->language);
//}
//
void free_dwarf2_per_objfile(struct dwarf2_per_objfile *dwarf2_per_objfile){
if(dwarf2_per_objfile->info_buffer){
free(dwarf2_per_objfile->info_buffer);
}
if(dwarf2_per_objfile->abbrev_buffer){
free(dwarf2_per_objfile->abbrev_buffer);
}
if(dwarf2_per_objfile->line_buffer){
free(dwarf2_per_objfile->line_buffer);
}
if(dwarf2_per_objfile->pubnames_buffer){
free(dwarf2_per_objfile->pubnames_buffer);
}
if(dwarf2_per_objfile->aranges_buffer){
free(dwarf2_per_objfile->aranges_buffer);
}
if(dwarf2_per_objfile->loc_buffer){
free(dwarf2_per_objfile->loc_buffer);
}
if(dwarf2_per_objfile->macinfo_buffer){
free(dwarf2_per_objfile->macinfo_buffer);
}
if(dwarf2_per_objfile->str_buffer){
free(dwarf2_per_objfile->str_buffer);
}
if(dwarf2_per_objfile->ranges_buffer){
free(dwarf2_per_objfile->ranges_buffer);
}
if(dwarf2_per_objfile->inlined_buffer){
free(dwarf2_per_objfile->inlined_buffer);
}
if(dwarf2_per_objfile->pubtypes_buffer){
free(dwarf2_per_objfile->pubtypes_buffer);
}
if(dwarf2_per_objfile->frame_buffer){
free(dwarf2_per_objfile->frame_buffer);
}
if(dwarf2_per_objfile->eh_frame_buffer){
free(dwarf2_per_objfile->eh_frame_buffer);
}
free(dwarf2_per_objfile);
}
void get_uuid_of_thin(struct thin_macho*thin_macho, char*uuid){
int i = 0;
while(i < 16){
sprintf(uuid + (i * 2), "%02x", thin_macho->uuid[i]);
i++;
}
}
static struct dwarf2_per_objfile* parse_dwarf_segment(char *macho_str, long offset,struct segment_command *command){
uint32_t numofdwarfsections = command->nsects;
struct dwarf2_per_objfile *dwarf2_per_objfile = malloc(sizeof(struct dwarf2_per_objfile));
if (dwarf2_per_objfile == NULL){
printf("Malloc Error!\n");
PyErr_NoMemory();
return NULL;
}
memset(dwarf2_per_objfile, '\0', sizeof(struct dwarf2_per_objfile));
struct section * dwarf_section_headers = malloc(numofdwarfsections * sizeof(struct section));
if (dwarf_section_headers == NULL){
printf("Malloc Error!\n");
PyErr_NoMemory();
return NULL;
}
memset(dwarf_section_headers, '\0', numofdwarfsections * sizeof (struct section));
memcpy(dwarf_section_headers, macho_str + offset, numofdwarfsections * sizeof(struct section));
uint32_t i = 0;
while(i < numofdwarfsections){
char *temp = malloc(dwarf_section_headers[i].size);
if (temp == NULL){