Coverage Report

Created: 2023-06-29 07:09

/src/binutils-gdb/bfd/pei-x86_64.c
Line
Count
Source (jump to first uncovered line)
1
/* BFD back-end for Intel 386 PE IMAGE COFF files.
2
   Copyright (C) 2006-2023 Free Software Foundation, Inc.
3
4
   This file is part of BFD, the Binary File Descriptor library.
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.
20
21
   Written by Kai Tietz, OneVision Software GmbH&CoKg.  */
22
23
#include "sysdep.h"
24
#include "bfd.h"
25
26
#define TARGET_SYM    x86_64_pei_vec
27
#define TARGET_NAME   "pei-x86-64"
28
#define COFF_IMAGE_WITH_PE
29
#define COFF_WITH_PE
30
#define COFF_WITH_pex64
31
#define PCRELOFFSET   true
32
#if defined (USE_MINGW64_LEADING_UNDERSCORES)
33
#define TARGET_UNDERSCORE '_'
34
#else
35
0
#define TARGET_UNDERSCORE 0
36
#endif
37
/* Long section names not allowed in executable images, only object files.  */
38
#define COFF_LONG_SECTION_NAMES 0
39
#define COFF_SUPPORT_GNU_LINKONCE
40
#define COFF_LONG_FILENAMES
41
0
#define PDATA_ROW_SIZE  (3 * 4)
42
43
#define COFF_SECTION_ALIGNMENT_ENTRIES \
44
{ COFF_SECTION_NAME_EXACT_MATCH (".bss"), \
45
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
46
{ COFF_SECTION_NAME_PARTIAL_MATCH (".data"), \
47
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
48
{ COFF_SECTION_NAME_PARTIAL_MATCH (".rdata"), \
49
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
50
{ COFF_SECTION_NAME_PARTIAL_MATCH (".text"), \
51
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
52
{ COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \
53
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
54
{ COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \
55
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \
56
{ COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
57
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
58
{ COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \
59
  COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
60
61
/* Note we have to make sure not to include headers twice.
62
   Not all headers are wrapped in #ifdef guards, so we define
63
   PEI_HEADERS to prevent double including in coff-x86_64.c  */
64
#define PEI_HEADERS
65
#include "sysdep.h"
66
#include "bfd.h"
67
#include "libbfd.h"
68
#include "coff/x86_64.h"
69
#include "coff/internal.h"
70
#include "coff/pe.h"
71
#include "libcoff.h"
72
#include "libpei.h"
73
#include "libiberty.h"
74
75
#undef AOUTSZ
76
#define AOUTSZ    PEPAOUTSZ
77
#define PEAOUTHDR PEPAOUTHDR
78
79
/* Name of registers according to SEH conventions.  */
80
81
static const char * const pex_regs[16] = {
82
  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
83
  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
84
};
85
86
/* Swap in a runtime function.  */
87
88
static void
89
pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
90
          const void *data)
91
0
{
92
0
  const struct external_pex64_runtime_function *ex_rf =
93
0
    (const struct external_pex64_runtime_function *) data;
94
0
  rf->rva_BeginAddress = bfd_get_32 (abfd, ex_rf->rva_BeginAddress);
95
0
  rf->rva_EndAddress = bfd_get_32 (abfd, ex_rf->rva_EndAddress);
96
0
  rf->rva_UnwindData =  bfd_get_32 (abfd, ex_rf->rva_UnwindData);
97
0
}
98
99
/* Swap in unwind info header.  */
100
101
static bool
102
pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui,
103
           void *data, void *data_end)
104
0
{
105
0
  struct external_pex64_unwind_info *ex_ui =
106
0
    (struct external_pex64_unwind_info *) data;
107
0
  bfd_byte *ex_dta = (bfd_byte *) data;
108
0
  bfd_byte *ex_dta_end = (bfd_byte *) data_end;
109
110
0
  memset (ui, 0, sizeof (struct pex64_unwind_info));
111
112
0
  if (ex_dta_end - ex_dta < 4)
113
0
    return false;
114
115
0
  ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags);
116
0
  ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags);
117
0
  ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue;
118
0
  ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes;
119
0
  ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset);
120
0
  ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset);
121
0
  ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes);
122
0
  ui->SizeOfBlock = ui->sizeofUnwindCodes + 4;
123
0
  ui->rawUnwindCodes = ex_dta + 4;
124
0
  ui->rawUnwindCodesEnd = ex_dta_end;
125
126
0
  if ((size_t) (ex_dta_end - ex_dta) < ui->SizeOfBlock)
127
0
    return false;
128
0
  ex_dta += ui->SizeOfBlock;
129
130
0
  switch (ui->Flags)
131
0
    {
132
0
    case UNW_FLAG_CHAININFO:
133
0
      if (ex_dta_end - ex_dta < 12)
134
0
  return false;
135
0
      ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0);
136
0
      ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4);
137
0
      ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8);
138
0
      ui->SizeOfBlock += 12;
139
0
      return true;
140
0
    case UNW_FLAG_EHANDLER:
141
0
    case UNW_FLAG_UHANDLER:
142
0
    case UNW_FLAG_FHANDLER:
143
0
      if (ex_dta_end - ex_dta < 4)
144
0
  return false;
145
0
      ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta);
146
0
      ui->SizeOfBlock += 4;
147
0
      return true;
148
0
    default:
149
0
      return true;
150
0
    }
151
0
}
152
153
/* Display unwind codes.  */
154
155
static void
156
pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
157
           struct pex64_unwind_info *ui,
158
           struct pex64_runtime_function *rf)
159
0
{
160
0
  unsigned int i;
161
0
  unsigned int tmp; /* At least 32 bits.  */
162
0
  int save_allowed;
163
164
0
  if (ui->CountOfCodes == 0 || ui->rawUnwindCodes == NULL)
165
0
    return;
166
167
  /* According to UNWIND_CODE documentation:
168
      If an FP reg is used, the any unwind code taking an offset must only be
169
      used after the FP reg is established in the prolog.
170
     But there are counter examples of that in system dlls...  */
171
0
  save_allowed = true;
172
173
0
  i = 0;
174
175
0
  if ((size_t) (ui->rawUnwindCodesEnd - ui->rawUnwindCodes)
176
0
      < ui->CountOfCodes * 2)
177
0
    {
178
0
      fprintf (file, _("warning: corrupt unwind data\n"));
179
0
      return;
180
0
    }
181
182
0
  if (ui->Version == 2
183
0
      && PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == UWOP_EPILOG)
184
0
    {
185
      /* Display epilog opcode (whose docoding is not fully documented).
186
   Looks to be designed to speed-up unwinding, as there is no need
187
   to decode instruction flow if outside an epilog.  */
188
0
      unsigned int func_size = rf->rva_EndAddress - rf->rva_BeginAddress;
189
190
0
      fprintf (file, "\tv2 epilog (length: %02x) at pc+:",
191
0
         ui->rawUnwindCodes[0]);
192
193
0
      if (PEX64_UNWCODE_INFO (ui->rawUnwindCodes[1]))
194
0
  fprintf (file, " 0x%x", func_size - ui->rawUnwindCodes[0]);
195
196
0
      i++;
197
0
      for (; i < ui->CountOfCodes; i++)
198
0
  {
199
0
    const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
200
0
    unsigned int off;
201
202
0
    if (PEX64_UNWCODE_CODE (dta[1]) != UWOP_EPILOG)
203
0
      break;
204
0
    off = dta[0] | (PEX64_UNWCODE_INFO (dta[1]) << 8);
205
0
    if (off == 0)
206
0
      fprintf (file, " [pad]");
207
0
    else
208
0
      fprintf (file, " 0x%x", func_size - off);
209
0
  }
210
0
      fputc ('\n', file);
211
0
    }
212
213
0
  for (; i < ui->CountOfCodes; i++)
214
0
    {
215
0
      const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
216
0
      unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
217
0
      int unexpected = false;
218
219
0
      fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
220
221
0
      switch (PEX64_UNWCODE_CODE (dta[1]))
222
0
  {
223
0
  case UWOP_PUSH_NONVOL:
224
0
    fprintf (file, "push %s", pex_regs[info]);
225
0
    break;
226
227
0
  case UWOP_ALLOC_LARGE:
228
0
    if (info == 0)
229
0
      {
230
0
        if (ui->rawUnwindCodesEnd - dta < 4)
231
0
    {
232
0
      fprintf (file, _("warning: corrupt unwind data\n"));
233
0
      return;
234
0
    }
235
0
        tmp = bfd_get_16 (abfd, dta + 2) * 8;
236
0
        i++;
237
0
      }
238
0
    else
239
0
      {
240
0
        if (ui->rawUnwindCodesEnd - dta < 6)
241
0
    {
242
0
      fprintf (file, _("warning: corrupt unwind data\n"));
243
0
      return;
244
0
    }
245
0
        tmp = bfd_get_32 (abfd, dta + 2);
246
0
        i += 2;
247
0
      }
248
0
    fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
249
0
    break;
250
251
0
  case UWOP_ALLOC_SMALL:
252
0
    fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
253
0
    break;
254
255
0
  case UWOP_SET_FPREG:
256
    /* According to the documentation, info field is unused.  */
257
0
    fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
258
0
       pex_regs[ui->FrameRegister],
259
0
       (unsigned int) ui->FrameOffset * 16, info);
260
0
    unexpected = ui->FrameRegister == 0;
261
0
    save_allowed = false;
262
0
    break;
263
264
0
  case UWOP_SAVE_NONVOL:
265
0
    if (ui->rawUnwindCodesEnd - dta < 4)
266
0
      {
267
0
        fprintf (file, _("warning: corrupt unwind data\n"));
268
0
        return;
269
0
      }
270
0
    tmp = bfd_get_16 (abfd, dta + 2) * 8;
271
0
    i++;
272
0
    fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
273
0
    unexpected = !save_allowed;
274
0
    break;
275
276
0
  case UWOP_SAVE_NONVOL_FAR:
277
0
    if (ui->rawUnwindCodesEnd - dta < 6)
278
0
      {
279
0
        fprintf (file, _("warning: corrupt unwind data\n"));
280
0
        return;
281
0
      }
282
0
    tmp = bfd_get_32 (abfd, dta + 2);
283
0
    i += 2;
284
0
    fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
285
0
    unexpected = !save_allowed;
286
0
    break;
287
288
0
  case UWOP_SAVE_XMM:
289
0
    if (ui->Version == 1)
290
0
      {
291
0
        if (ui->rawUnwindCodesEnd - dta < 4)
292
0
    {
293
0
      fprintf (file, _("warning: corrupt unwind data\n"));
294
0
      return;
295
0
    }
296
0
        tmp = bfd_get_16 (abfd, dta + 2) * 8;
297
0
        i++;
298
0
        fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
299
0
        unexpected = !save_allowed;
300
0
      }
301
0
    else if (ui->Version == 2)
302
0
      {
303
0
        fprintf (file, "epilog %02x %01x", dta[0], info);
304
0
        unexpected = true;
305
0
      }
306
0
    break;
307
308
0
  case UWOP_SAVE_XMM_FAR:
309
0
    if (ui->rawUnwindCodesEnd - dta < 6)
310
0
      {
311
0
        fprintf (file, _("warning: corrupt unwind data\n"));
312
0
        return;
313
0
      }
314
0
    tmp = bfd_get_32 (abfd, dta + 2) * 8;
315
0
    i += 2;
316
0
    fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
317
0
    unexpected = !save_allowed;
318
0
    break;
319
320
0
  case UWOP_SAVE_XMM128:
321
0
    if (ui->rawUnwindCodesEnd - dta < 4)
322
0
      {
323
0
        fprintf (file, _("warning: corrupt unwind data\n"));
324
0
        return;
325
0
      }
326
0
    tmp = bfd_get_16 (abfd, dta + 2) * 16;
327
0
    i++;
328
0
    fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
329
0
    unexpected = !save_allowed;
330
0
    break;
331
332
0
  case UWOP_SAVE_XMM128_FAR:
333
0
    if (ui->rawUnwindCodesEnd - dta < 6)
334
0
      {
335
0
        fprintf (file, _("warning: corrupt unwind data\n"));
336
0
        return;
337
0
      }
338
0
    tmp = bfd_get_32 (abfd, dta + 2) * 16;
339
0
    i += 2;
340
0
    fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
341
0
    unexpected = !save_allowed;
342
0
    break;
343
344
0
  case UWOP_PUSH_MACHFRAME:
345
0
    fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
346
0
    if (info == 0)
347
0
      fprintf (file, ")");
348
0
    else if (info == 1)
349
0
      fprintf (file, ",ErrorCode)");
350
0
    else
351
0
      fprintf (file, ", unknown(%u))", info);
352
0
    break;
353
354
0
  default:
355
    /* PR 17512: file: 2245-7442-0.004.  */
356
0
    fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
357
0
    break;
358
0
  }
359
360
0
      if (unexpected)
361
0
  fprintf (file, " [Unexpected!]");
362
0
      fputc ('\n', file);
363
0
    }
364
0
}
365
366
/* Check wether section SEC_NAME contains the xdata at address ADDR.  */
367
368
static asection *
369
pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name)
370
0
{
371
0
  asection *section = bfd_get_section_by_name (abfd, sec_name);
372
0
  bfd_vma vsize;
373
0
  bfd_size_type datasize = 0;
374
375
0
  if (section == NULL
376
0
      || coff_section_data (abfd, section) == NULL
377
0
      || pei_section_data (abfd, section) == NULL)
378
0
    return NULL;
379
0
  vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
380
0
  datasize = section->size;
381
0
  if (!datasize || vsize > addr || (vsize + datasize) < addr)
382
0
    return NULL;
383
0
  return section;
384
0
}
385
386
/* Dump xdata at for function RF to FILE.  The argument XDATA_SECTION
387
   designate the bfd section containing the xdata, XDATA is its content,
388
   and ENDX the size if known (or NULL).  */
389
390
static void
391
pex64_dump_xdata (FILE *file, bfd *abfd,
392
      asection *xdata_section, bfd_byte *xdata, bfd_vma *endx,
393
      struct pex64_runtime_function *rf)
394
0
{
395
0
  bfd_vma vaddr;
396
0
  bfd_vma end_addr;
397
0
  bfd_vma addr = rf->rva_UnwindData;
398
0
  bfd_size_type sec_size = xdata_section->rawsize > 0 ? xdata_section->rawsize : xdata_section->size;
399
0
  struct pex64_unwind_info ui;
400
401
0
  vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
402
0
  addr -= vaddr;
403
404
  /* PR 17512: file: 2245-7442-0.004.  */
405
0
  if (addr >= sec_size)
406
0
    {
407
0
      fprintf (file, _("warning: xdata section corrupt\n"));
408
0
      return;
409
0
    }
410
411
0
  if (endx)
412
0
    {
413
0
      end_addr = endx[0] - vaddr;
414
      /* PR 17512: file: 2245-7442-0.004.  */
415
0
      if (end_addr > sec_size)
416
0
  {
417
0
    fprintf (file, _("warning: xdata section corrupt\n"));
418
0
    end_addr = sec_size;
419
0
  }
420
0
    }
421
0
  else
422
0
    end_addr = sec_size;
423
424
0
  if (! pex64_get_unwind_info (abfd, &ui, xdata + addr, xdata + end_addr))
425
0
    {
426
0
      fprintf (file, _("warning: xdata section corrupt\n"));
427
0
      return;
428
0
    }
429
430
0
  if (ui.Version != 1 && ui.Version != 2)
431
0
    {
432
0
      unsigned int i;
433
0
      fprintf (file, "\tVersion %u (unknown).\n",
434
0
         (unsigned int) ui.Version);
435
0
      for (i = 0; addr < end_addr; addr += 1, i++)
436
0
  {
437
0
    if ((i & 15) == 0)
438
0
      fprintf (file, "\t  %03x:", i);
439
0
    fprintf (file, " %02x", xdata[addr]);
440
0
    if ((i & 15) == 15)
441
0
      fprintf (file, "\n");
442
0
  }
443
0
      if ((i & 15) != 0)
444
0
  fprintf (file, "\n");
445
0
      return;
446
0
    }
447
448
0
  fprintf (file, "\tVersion: %d, Flags: ", ui.Version);
449
0
  switch (ui.Flags)
450
0
    {
451
0
    case UNW_FLAG_NHANDLER:
452
0
      fprintf (file, "none");
453
0
      break;
454
0
    case UNW_FLAG_EHANDLER:
455
0
      fprintf (file, "UNW_FLAG_EHANDLER");
456
0
      break;
457
0
    case UNW_FLAG_UHANDLER:
458
0
      fprintf (file, "UNW_FLAG_UHANDLER");
459
0
      break;
460
0
    case UNW_FLAG_FHANDLER:
461
0
      fprintf
462
0
  (file, "UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER");
463
0
      break;
464
0
    case UNW_FLAG_CHAININFO:
465
0
      fprintf (file, "UNW_FLAG_CHAININFO");
466
0
      break;
467
0
    default:
468
0
      fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
469
0
      break;
470
0
    }
471
0
  fputc ('\n', file);
472
0
  fprintf (file, "\tNbr codes: %u, ", (unsigned int) ui.CountOfCodes);
473
0
  fprintf (file, "Prologue size: 0x%02x, Frame offset: 0x%x, ",
474
0
     (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
475
0
  fprintf (file, "Frame reg: %s\n",
476
0
     ui.FrameRegister == 0 ? "none"
477
0
     : pex_regs[(unsigned int) ui.FrameRegister]);
478
479
  /* PR 17512: file: 2245-7442-0.004.  */
480
0
  if (ui.CountOfCodes * 2 + ui.rawUnwindCodes > xdata + xdata_section->size)
481
0
    fprintf (file, _("Too many unwind codes (%ld)\n"), (long) ui.CountOfCodes);
482
0
  else
483
0
    pex64_xdata_print_uwd_codes (file, abfd, &ui, rf);
484
485
0
  switch (ui.Flags)
486
0
    {
487
0
    case UNW_FLAG_EHANDLER:
488
0
    case UNW_FLAG_UHANDLER:
489
0
    case UNW_FLAG_FHANDLER:
490
0
      fprintf (file, "\tHandler: %016" PRIx64 ".\n",
491
0
         ui.rva_ExceptionHandler + pe_data (abfd)->pe_opthdr.ImageBase);
492
0
      break;
493
0
    case UNW_FLAG_CHAININFO:
494
0
      fprintf (file, "\tChain: start: %016" PRIx64 ", end: %016" PRIx64,
495
0
         ui.rva_BeginAddress, ui.rva_EndAddress);
496
0
      fprintf (file, "\n\t unwind data: %016" PRIx64 ".\n",
497
0
         ui.rva_UnwindData);
498
0
      break;
499
0
    }
500
501
  /* Now we need end of this xdata block.  */
502
0
  addr += ui.SizeOfBlock;
503
0
  if (addr < end_addr)
504
0
    {
505
0
      unsigned int i;
506
0
      fprintf (file,"\tUser data:\n");
507
0
      for (i = 0; addr < end_addr; addr += 1, i++)
508
0
  {
509
0
    if ((i & 15) == 0)
510
0
      fprintf (file, "\t  %03x:", i);
511
0
    fprintf (file, " %02x", xdata[addr]);
512
0
    if ((i & 15) == 15)
513
0
      fprintf (file, "\n");
514
0
  }
515
0
      if ((i & 15) != 0)
516
0
  fprintf (file, "\n");
517
0
    }
518
0
}
519
520
/* Helper function to sort xdata.  The entries of xdata are sorted to know
521
   the size of each entry.  */
522
523
static int
524
sort_xdata_arr (const void *l, const void *r)
525
0
{
526
0
  const bfd_vma *lp = (const bfd_vma *) l;
527
0
  const bfd_vma *rp = (const bfd_vma *) r;
528
529
0
  if (*lp == *rp)
530
0
    return 0;
531
0
  return (*lp < *rp ? -1 : 1);
532
0
}
533
534
/* Display unwind tables for x86-64.  */
535
536
static bool
537
pex64_bfd_print_pdata_section (bfd *abfd, void *vfile, asection *pdata_section)
538
0
{
539
0
  FILE *file = (FILE *) vfile;
540
0
  bfd_byte *pdata = NULL;
541
0
  bfd_byte *xdata = NULL;
542
0
  asection *xdata_section = NULL;
543
0
  bfd_vma xdata_base;
544
0
  bfd_size_type i;
545
0
  bfd_size_type datasize;
546
0
  bfd_size_type stop;
547
0
  bfd_vma prev_beginaddress = (bfd_vma) -1;
548
0
  bfd_vma prev_unwinddata_rva = (bfd_vma) -1;
549
0
  bfd_vma imagebase;
550
0
  int onaline = PDATA_ROW_SIZE;
551
0
  int seen_error = 0;
552
0
  bfd_vma *xdata_arr = NULL;
553
0
  int xdata_arr_cnt;
554
0
  bool virt_size_is_zero = false;
555
556
  /* Sanity checks.  */
557
0
  if (pdata_section == NULL
558
0
      || (pdata_section->flags & SEC_HAS_CONTENTS) == 0
559
0
      || coff_section_data (abfd, pdata_section) == NULL
560
0
      || pei_section_data (abfd, pdata_section) == NULL)
561
0
    return true;
562
563
0
  stop = pei_section_data (abfd, pdata_section)->virt_size;
564
0
  if ((stop % onaline) != 0)
565
0
    fprintf (file,
566
       /* xgettext:c-format */
567
0
       _("Warning: %s section size (%ld) is not a multiple of %d\n"),
568
0
       pdata_section->name, (long) stop, onaline);
569
570
0
  datasize = pdata_section->size;
571
0
  if (datasize == 0)
572
0
    {
573
0
      if (stop)
574
0
  fprintf (file, _("Warning: %s section size is zero\n"),
575
0
     pdata_section->name);
576
0
      return true;
577
0
    }
578
579
  /* virt_size might be zero for objects.  */
580
0
  if (stop == 0 && strcmp (abfd->xvec->name, "pe-x86-64") == 0)
581
0
    {
582
0
      stop = datasize;
583
0
      virt_size_is_zero = true;
584
0
    }
585
0
  else if (datasize < stop)
586
0
      {
587
0
  fprintf (file,
588
     /* xgettext:c-format */
589
0
     _("Warning: %s section size (%ld) is smaller than virtual size (%ld)\n"),
590
0
     pdata_section->name, (unsigned long) datasize,
591
0
     (unsigned long) stop);
592
  /* Be sure not to read past datasize.  */
593
0
  stop = datasize;
594
0
      }
595
596
  /* Display functions table.  */
597
0
  fprintf (file,
598
0
     _("\nThe Function Table (interpreted %s section contents)\n"),
599
0
     pdata_section->name);
600
601
0
  fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t  UnwindData\n"));
602
603
0
  if (!bfd_malloc_and_get_section (abfd, pdata_section, &pdata))
604
0
    goto done;
605
606
  /* Table of xdata entries.  */
607
0
  xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
608
0
  xdata_arr_cnt = 0;
609
610
0
  if (strcmp (abfd->xvec->name, "pei-x86-64") == 0)
611
0
    imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
612
0
  else
613
0
    imagebase = 0;
614
615
0
  for (i = 0; i < stop; i += onaline)
616
0
    {
617
0
      struct pex64_runtime_function rf;
618
619
0
      if (i + PDATA_ROW_SIZE > stop)
620
0
  break;
621
622
0
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
623
624
0
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
625
0
    && rf.rva_UnwindData == 0)
626
  /* We are probably into the padding of the section now.  */
627
0
  break;
628
0
      fprintf (file, " %016" PRIx64, i + pdata_section->vma);
629
0
      fprintf (file, ":\t%016" PRIx64, imagebase + rf.rva_BeginAddress);
630
0
      fprintf (file, " %016" PRIx64, imagebase + rf.rva_EndAddress);
631
0
      fprintf (file, " %016" PRIx64 "\n", imagebase + rf.rva_UnwindData);
632
0
      if (i != 0 && rf.rva_BeginAddress <= prev_beginaddress)
633
0
  {
634
0
    seen_error = 1;
635
0
    fprintf (file, "  has %s begin address as predecessor\n",
636
0
      (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same"));
637
0
  }
638
0
      prev_beginaddress = rf.rva_BeginAddress;
639
      /* Now we check for negative addresses.  */
640
0
      if ((prev_beginaddress & 0x80000000) != 0)
641
0
  {
642
0
    seen_error = 1;
643
0
    fprintf (file, "  has negative begin address\n");
644
0
  }
645
0
      if ((rf.rva_EndAddress & 0x80000000) != 0)
646
0
  {
647
0
    seen_error = 1;
648
0
    fprintf (file, "  has negative end address\n");
649
0
  }
650
0
      if ((rf.rva_UnwindData & 0x80000000) != 0)
651
0
  {
652
0
    seen_error = 1;
653
0
    fprintf (file, "  has negative unwind address\n");
654
0
  }
655
0
      else if ((rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
656
0
    || virt_size_is_zero)
657
0
  xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
658
0
    }
659
660
0
  if (seen_error)
661
0
    goto done;
662
663
  /* Add end of list marker.  */
664
0
  xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);
665
666
  /* Sort start RVAs of xdata.  */
667
0
  if (xdata_arr_cnt > 1)
668
0
    qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
669
0
     sort_xdata_arr);
670
671
  /* Find the section containing the unwind data (.xdata).  */
672
0
  xdata_base = xdata_arr[0];
673
  /* For sections with long names, first look for the same
674
     section name, replacing .pdata by .xdata prefix.  */
675
0
  if (strcmp (pdata_section->name, ".pdata") != 0)
676
0
    {
677
0
      size_t len = strlen (pdata_section->name);
678
0
      char *xdata_name = xmalloc (len + 1);
679
680
0
      xdata_name = memcpy (xdata_name, pdata_section->name, len + 1);
681
      /* Transform .pdata prefix into .xdata prefix.  */
682
0
      if (len > 1)
683
0
  xdata_name [1] = 'x';
684
0
      xdata_section = pex64_get_section_by_rva (abfd, xdata_base,
685
0
            xdata_name);
686
0
      free (xdata_name);
687
0
    }
688
  /* Second, try the .xdata section itself.  */
689
0
  if (!xdata_section)
690
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata");
691
  /* Otherwise, if xdata_base is non zero, search also inside
692
     other standard sections.  */
693
0
  if (!xdata_section && xdata_base)
694
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata");
695
0
  if (!xdata_section && xdata_base)
696
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data");
697
0
  if (!xdata_section && xdata_base)
698
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata");
699
0
  if (!xdata_section && xdata_base)
700
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
701
  /* Transfer xdata section into xdata array.  */
702
0
  if (!xdata_section
703
0
      || (xdata_section->flags & SEC_HAS_CONTENTS) == 0
704
0
      || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata))
705
0
    goto done;
706
707
  /* Avoid "also used "... ouput for single unwind info
708
     in object file.  */
709
0
  prev_unwinddata_rva = (bfd_vma) -1;
710
711
  /* Do dump of pdata related xdata.  */
712
0
  for (i = 0; i < stop; i += onaline)
713
0
    {
714
0
      struct pex64_runtime_function rf;
715
716
0
      if (i + PDATA_ROW_SIZE > stop)
717
0
  break;
718
719
0
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
720
721
0
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
722
0
    && rf.rva_UnwindData == 0)
723
  /* We are probably into the padding of the section now.  */
724
0
  break;
725
0
      if (i == 0)
726
0
  fprintf (file, _("\nDump of %s\n"), xdata_section->name);
727
728
0
      fprintf (file, " %016" PRIx64, rf.rva_UnwindData + imagebase);
729
730
0
      if (prev_unwinddata_rva == rf.rva_UnwindData)
731
0
  {
732
    /* Do not dump again the xdata for the same entry.  */
733
0
    fprintf (file, " also used for function at %016" PRIx64 "\n",
734
0
       rf.rva_BeginAddress + imagebase);
735
0
    continue;
736
0
  }
737
0
      else
738
0
  prev_unwinddata_rva = rf.rva_UnwindData;
739
740
0
      fprintf (file, " (rva: %08x): %016" PRIx64 " - %016" PRIx64 "\n",
741
0
         (unsigned int) rf.rva_UnwindData,
742
0
         rf.rva_BeginAddress + imagebase,
743
0
         rf.rva_EndAddress + imagebase);
744
745
0
      if (rf.rva_UnwindData != 0 || virt_size_is_zero)
746
0
  {
747
0
    if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
748
0
      {
749
0
        bfd_vma altent = PEX64_GET_UNWINDDATA_UNIFIED_RVA (&rf);
750
0
        bfd_vma pdata_vma = bfd_section_vma (pdata_section);
751
0
        struct pex64_runtime_function arf;
752
753
0
        fprintf (file, "\t shares information with ");
754
0
        altent += imagebase;
755
756
0
        if (altent >= pdata_vma
757
0
      && altent - pdata_vma + PDATA_ROW_SIZE <= stop)
758
0
    {
759
0
      pex64_get_runtime_function
760
0
        (abfd, &arf, &pdata[altent - pdata_vma]);
761
0
      fprintf (file, "pdata element at 0x%016" PRIx64,
762
0
         arf.rva_UnwindData);
763
0
    }
764
0
        else
765
0
    fprintf (file, "unknown pdata element");
766
0
        fprintf (file, ".\n");
767
0
      }
768
0
    else
769
0
      {
770
0
        bfd_vma *p;
771
772
        /* Search for the current entry in the sorted array.  */
773
0
        p = (bfd_vma *)
774
0
      bsearch (&rf.rva_UnwindData, xdata_arr,
775
0
         (size_t) xdata_arr_cnt, sizeof (bfd_vma),
776
0
         sort_xdata_arr);
777
778
        /* Advance to the next pointer into the xdata section.  We may
779
     have shared xdata entries, which will result in a string of
780
     identical pointers in the array; advance past all of them.  */
781
0
        while (p[0] <= rf.rva_UnwindData)
782
0
    ++p;
783
784
0
        if (p[0] == ~((bfd_vma) 0))
785
0
    p = NULL;
786
787
0
        pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
788
0
      }
789
0
  }
790
0
    }
791
792
0
 done:
793
0
  free (pdata);
794
0
  free (xdata_arr);
795
0
  free (xdata);
796
797
0
  return true;
798
0
}
799
800
struct pex64_paps
801
{
802
  void *obj;
803
  /* Number of found pdata sections.  */
804
  unsigned int pdata_count;
805
};
806
807
/* Functionn prototype.  */
808
bool pex64_bfd_print_pdata (bfd *, void *);
809
810
/* Helper function for bfd_map_over_section.  */
811
static void
812
pex64_print_all_pdata_sections (bfd *abfd, asection *pdata, void *arg)
813
0
{
814
0
  struct pex64_paps *paps = arg;
815
0
  if (startswith (pdata->name, ".pdata"))
816
0
    {
817
0
      if (pex64_bfd_print_pdata_section (abfd, paps->obj, pdata))
818
0
  paps->pdata_count++;
819
0
    }
820
0
}
821
822
bool
823
pex64_bfd_print_pdata (bfd *abfd, void *vfile)
824
0
{
825
0
  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
826
0
  struct pex64_paps paps;
827
828
0
  if (pdata_section)
829
0
    return pex64_bfd_print_pdata_section (abfd, vfile, pdata_section);
830
831
0
  paps.obj = vfile;
832
0
  paps.pdata_count = 0;
833
0
  bfd_map_over_sections (abfd, pex64_print_all_pdata_sections, &paps);
834
0
  return paps.pdata_count != 0;
835
0
}
836
837
#define bfd_pe_print_pdata   pex64_bfd_print_pdata
838
#define bfd_coff_std_swap_table bfd_coff_pei_swap_table
839
840
#include "coff-x86_64.c"