Coverage Report

Created: 2026-07-25 10:20

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