Coverage Report

Created: 2026-03-10 08:46

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
3.67k
#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
243
#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
228
{
88
228
  const struct external_pex64_runtime_function *ex_rf =
89
228
    (const struct external_pex64_runtime_function *) data;
90
228
  rf->rva_BeginAddress = bfd_get_32 (abfd, ex_rf->rva_BeginAddress);
91
228
  rf->rva_EndAddress = bfd_get_32 (abfd, ex_rf->rva_EndAddress);
92
228
  rf->rva_UnwindData =  bfd_get_32 (abfd, ex_rf->rva_UnwindData);
93
228
}
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
2
{
101
2
  struct external_pex64_unwind_info *ex_ui =
102
2
    (struct external_pex64_unwind_info *) data;
103
2
  bfd_byte *ex_dta = (bfd_byte *) data;
104
2
  bfd_byte *ex_dta_end = (bfd_byte *) data_end;
105
106
2
  memset (ui, 0, sizeof (struct pex64_unwind_info));
107
108
2
  if (ex_dta_end - ex_dta < 4)
109
0
    return false;
110
111
2
  ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags);
112
2
  ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags);
113
2
  ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue;
114
2
  ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes;
115
2
  ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset);
116
2
  ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset);
117
2
  ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes);
118
2
  ui->SizeOfBlock = ui->sizeofUnwindCodes + 4;
119
2
  ui->rawUnwindCodes = ex_dta + 4;
120
2
  ui->rawUnwindCodesEnd = ex_dta_end;
121
122
2
  if ((size_t) (ex_dta_end - ex_dta) < ui->SizeOfBlock)
123
1
    return false;
124
1
  ex_dta += ui->SizeOfBlock;
125
126
1
  switch (ui->Flags)
127
1
    {
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
1
    default:
145
1
      return true;
146
1
    }
147
1
}
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
1
{
156
1
  unsigned int i;
157
1
  unsigned int tmp; /* At least 32 bits.  */
158
1
  int save_allowed;
159
160
1
  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
1
  save_allowed = true;
168
169
1
  i = 0;
170
171
1
  if ((size_t) (ui->rawUnwindCodesEnd - ui->rawUnwindCodes)
172
1
      < ui->CountOfCodes * 2)
173
0
    {
174
0
      fprintf (file, _("warning: corrupt unwind data\n"));
175
0
      return;
176
0
    }
177
178
1
  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
70
  for (; i < ui->CountOfCodes; i++)
210
69
    {
211
69
      const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
212
69
      unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
213
69
      int unexpected = false;
214
215
69
      fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
216
217
69
      switch (PEX64_UNWCODE_CODE (dta[1]))
218
69
  {
219
3
  case UWOP_PUSH_NONVOL:
220
3
    fprintf (file, "push %s", pex_regs[info]);
221
3
    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
1
  case UWOP_ALLOC_SMALL:
248
1
    fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
249
1
    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
65
  default:
351
    /* PR 17512: file: 2245-7442-0.004.  */
352
65
    fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
353
65
    break;
354
69
  }
355
356
69
      if (unexpected)
357
0
  fprintf (file, " [Unexpected!]");
358
69
      fputc ('\n', file);
359
69
    }
360
1
}
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
4
{
367
4
  asection *section = bfd_get_section_by_name (abfd, sec_name);
368
4
  bfd_vma vsize;
369
4
  bfd_size_type datasize = 0;
370
371
4
  if (section == NULL
372
1
      || coff_section_data (abfd, section) == NULL
373
1
      || pei_section_data (abfd, section) == NULL)
374
3
    return NULL;
375
1
  vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
376
1
  datasize = section->size;
377
1
  if (!datasize || vsize > addr || (vsize + datasize) < addr)
378
0
    return NULL;
379
1
  return section;
380
1
}
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
2
{
391
2
  bfd_vma vaddr;
392
2
  bfd_vma end_addr;
393
2
  bfd_vma addr = rf->rva_UnwindData;
394
2
  bfd_size_type sec_size = xdata_section->rawsize > 0 ? xdata_section->rawsize : xdata_section->size;
395
2
  struct pex64_unwind_info ui;
396
397
2
  vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
398
2
  addr -= vaddr;
399
400
  /* PR 17512: file: 2245-7442-0.004.  */
401
2
  if (addr >= sec_size)
402
0
    {
403
0
      fprintf (file, _("warning: xdata section corrupt\n"));
404
0
      return;
405
0
    }
406
407
2
  if (endx)
408
1
    {
409
1
      end_addr = endx[0] - vaddr;
410
      /* PR 17512: file: 2245-7442-0.004.  */
411
1
      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
1
    }
417
1
  else
418
1
    end_addr = sec_size;
419
420
2
  if (! pex64_get_unwind_info (abfd, &ui, xdata + addr, xdata + end_addr))
421
1
    {
422
1
      fprintf (file, _("warning: xdata section corrupt\n"));
423
1
      return;
424
1
    }
425
426
1
  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
1
  fprintf (file, "\tVersion: %d, Flags: ", ui.Version);
445
1
  switch (ui.Flags)
446
1
    {
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
1
    default:
464
1
      fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
465
1
      break;
466
1
    }
467
1
  fputc ('\n', file);
468
1
  fprintf (file, "\tNbr codes: %u, ", (unsigned int) ui.CountOfCodes);
469
1
  fprintf (file, "Prologue size: 0x%02x, Frame offset: 0x%x, ",
470
1
     (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
471
1
  fprintf (file, "Frame reg: %s\n",
472
1
     ui.FrameRegister == 0 ? "none"
473
1
     : pex_regs[(unsigned int) ui.FrameRegister]);
474
475
  /* PR 17512: file: 2245-7442-0.004.  */
476
1
  if (ui.CountOfCodes * 2 + ui.rawUnwindCodes > xdata + xdata_section->size)
477
0
    fprintf (file, _("Too many unwind codes (%ld)\n"), (long) ui.CountOfCodes);
478
1
  else
479
1
    pex64_xdata_print_uwd_codes (file, abfd, &ui, rf);
480
481
1
  switch (ui.Flags)
482
1
    {
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
1
    }
496
497
  /* Now we need end of this xdata block.  */
498
1
  addr += ui.SizeOfBlock;
499
1
  if (addr < end_addr)
500
1
    {
501
1
      unsigned int i;
502
1
      fprintf (file,"\tUser data:\n");
503
277
      for (i = 0; addr < end_addr; addr += 1, i++)
504
276
  {
505
276
    if ((i & 15) == 0)
506
18
      fprintf (file, "\t  %03x:", i);
507
276
    fprintf (file, " %02x", xdata[addr]);
508
276
    if ((i & 15) == 15)
509
17
      fprintf (file, "\n");
510
276
  }
511
1
      if ((i & 15) != 0)
512
1
  fprintf (file, "\n");
513
1
    }
514
1
}
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
6
{
522
6
  const bfd_vma *lp = (const bfd_vma *) l;
523
6
  const bfd_vma *rp = (const bfd_vma *) r;
524
525
6
  if (*lp == *rp)
526
2
    return 0;
527
4
  return (*lp < *rp ? -1 : 1);
528
6
}
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
15
{
535
15
  FILE *file = (FILE *) vfile;
536
15
  bfd_byte *pdata = NULL;
537
15
  bfd_byte *xdata = NULL;
538
15
  asection *xdata_section = NULL;
539
15
  bfd_vma xdata_base;
540
15
  bfd_size_type i;
541
15
  bfd_size_type datasize;
542
15
  bfd_size_type stop;
543
15
  bfd_vma prev_beginaddress = (bfd_vma) -1;
544
15
  bfd_vma prev_unwinddata_rva = (bfd_vma) -1;
545
15
  bfd_vma imagebase;
546
15
  int onaline = PDATA_ROW_SIZE;
547
15
  int seen_error = 0;
548
15
  bfd_vma *xdata_arr = NULL;
549
15
  int xdata_arr_cnt;
550
15
  bool virt_size_is_zero = false;
551
552
  /* Sanity checks.  */
553
15
  if (pdata_section == NULL
554
15
      || (pdata_section->flags & SEC_HAS_CONTENTS) == 0
555
15
      || coff_section_data (abfd, pdata_section) == NULL
556
15
      || pei_section_data (abfd, pdata_section) == NULL)
557
0
    return true;
558
559
15
  stop = pei_section_data (abfd, pdata_section)->virt_size;
560
15
  if ((stop % onaline) != 0)
561
1
    fprintf (file,
562
       /* xgettext:c-format */
563
1
       _("Warning: %s section size (%ld) is not a multiple of %d\n"),
564
1
       pdata_section->name, (long) stop, onaline);
565
566
15
  datasize = pdata_section->size;
567
15
  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
15
  if (stop == 0 && strcmp (abfd->xvec->name, "pe-x86-64") == 0)
577
1
    {
578
1
      stop = datasize;
579
1
      virt_size_is_zero = true;
580
1
    }
581
14
  else if (datasize < stop)
582
1
      {
583
1
  fprintf (file,
584
     /* xgettext:c-format */
585
1
     _("Warning: %s section size (%ld) is smaller than virtual size (%ld)\n"),
586
1
     pdata_section->name, (unsigned long) datasize,
587
1
     (unsigned long) stop);
588
  /* Be sure not to read past datasize.  */
589
1
  stop = datasize;
590
1
      }
591
592
  /* Display functions table.  */
593
15
  fprintf (file,
594
15
     _("\nThe Function Table (interpreted %s section contents)\n"),
595
15
     pdata_section->name);
596
597
15
  fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t  UnwindData\n"));
598
599
15
  if (!bfd_malloc_and_get_section (abfd, pdata_section, &pdata))
600
13
    goto done;
601
602
  /* Table of xdata entries.  */
603
2
  xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
604
2
  xdata_arr_cnt = 0;
605
606
2
  if (strcmp (abfd->xvec->name, "pei-x86-64") == 0)
607
0
    imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
608
2
  else
609
2
    imagebase = 0;
610
611
225
  for (i = 0; i < stop; i += onaline)
612
225
    {
613
225
      struct pex64_runtime_function rf;
614
615
225
      if (i + PDATA_ROW_SIZE > stop)
616
0
  break;
617
618
225
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
619
620
225
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
621
7
    && rf.rva_UnwindData == 0)
622
  /* We are probably into the padding of the section now.  */
623
2
  break;
624
223
      fprintf (file, " %016" PRIx64, i + pdata_section->vma);
625
223
      fprintf (file, ":\t%016" PRIx64, imagebase + rf.rva_BeginAddress);
626
223
      fprintf (file, " %016" PRIx64, imagebase + rf.rva_EndAddress);
627
223
      fprintf (file, " %016" PRIx64 "\n", imagebase + rf.rva_UnwindData);
628
223
      if (i != 0 && rf.rva_BeginAddress <= prev_beginaddress)
629
126
  {
630
126
    seen_error = 1;
631
126
    fprintf (file, "  has %s begin address as predecessor\n",
632
126
      (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same"));
633
126
  }
634
223
      prev_beginaddress = rf.rva_BeginAddress;
635
      /* Now we check for negative addresses.  */
636
223
      if ((prev_beginaddress & 0x80000000) != 0)
637
42
  {
638
42
    seen_error = 1;
639
42
    fprintf (file, "  has negative begin address\n");
640
42
  }
641
223
      if ((rf.rva_EndAddress & 0x80000000) != 0)
642
60
  {
643
60
    seen_error = 1;
644
60
    fprintf (file, "  has negative end address\n");
645
60
  }
646
223
      if ((rf.rva_UnwindData & 0x80000000) != 0)
647
57
  {
648
57
    seen_error = 1;
649
57
    fprintf (file, "  has negative unwind address\n");
650
57
  }
651
166
      else if ((rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
652
51
    || virt_size_is_zero)
653
115
  xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
654
223
    }
655
656
2
  if (seen_error)
657
1
    goto done;
658
659
  /* Add end of list marker.  */
660
1
  xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);
661
662
  /* Sort start RVAs of xdata.  */
663
1
  if (xdata_arr_cnt > 1)
664
1
    qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
665
1
     sort_xdata_arr);
666
667
  /* Find the section containing the unwind data (.xdata).  */
668
1
  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
1
  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
1
  if (!xdata_section)
686
1
    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
1
  if (!xdata_section && xdata_base)
690
1
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata");
691
1
  if (!xdata_section && xdata_base)
692
1
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data");
693
1
  if (!xdata_section && xdata_base)
694
1
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata");
695
1
  if (!xdata_section && xdata_base)
696
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
697
  /* Transfer xdata section into xdata array.  */
698
1
  if (!xdata_section
699
1
      || (xdata_section->flags & SEC_HAS_CONTENTS) == 0
700
1
      || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata))
701
0
    goto done;
702
703
  /* Avoid "also used "... ouput for single unwind info
704
     in object file.  */
705
1
  prev_unwinddata_rva = (bfd_vma) -1;
706
707
  /* Do dump of pdata related xdata.  */
708
3
  for (i = 0; i < stop; i += onaline)
709
3
    {
710
3
      struct pex64_runtime_function rf;
711
712
3
      if (i + PDATA_ROW_SIZE > stop)
713
0
  break;
714
715
3
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
716
717
3
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
718
1
    && rf.rva_UnwindData == 0)
719
  /* We are probably into the padding of the section now.  */
720
1
  break;
721
2
      if (i == 0)
722
1
  fprintf (file, _("\nDump of %s\n"), xdata_section->name);
723
724
2
      fprintf (file, " %016" PRIx64, rf.rva_UnwindData + imagebase);
725
726
2
      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
2
      else
734
2
  prev_unwinddata_rva = rf.rva_UnwindData;
735
736
2
      fprintf (file, " (rva: %08x): %016" PRIx64 " - %016" PRIx64 "\n",
737
2
         (unsigned int) rf.rva_UnwindData,
738
2
         rf.rva_BeginAddress + imagebase,
739
2
         rf.rva_EndAddress + imagebase);
740
741
2
      if (rf.rva_UnwindData != 0 || virt_size_is_zero)
742
2
  {
743
2
    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
2
    else
765
2
      {
766
2
        bfd_vma *p;
767
768
        /* Search for the current entry in the sorted array.  */
769
2
        p = (bfd_vma *)
770
2
      bsearch (&rf.rva_UnwindData, xdata_arr,
771
2
         (size_t) xdata_arr_cnt, sizeof (bfd_vma),
772
2
         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
4
        while (p[0] <= rf.rva_UnwindData)
778
2
    ++p;
779
780
2
        if (p[0] == ~((bfd_vma) 0))
781
1
    p = NULL;
782
783
2
        pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
784
2
      }
785
2
  }
786
2
    }
787
788
15
 done:
789
15
  free (pdata);
790
15
  free (xdata_arr);
791
15
  free (xdata);
792
793
15
  return true;
794
1
}
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
4.45k
{
810
4.45k
  struct pex64_paps *paps = arg;
811
4.45k
  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
4.45k
}
817
818
bool
819
pex64_bfd_print_pdata (bfd *abfd, void *vfile)
820
237
{
821
237
  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
822
237
  struct pex64_paps paps;
823
824
237
  if (pdata_section)
825
13
    return pex64_bfd_print_pdata_section (abfd, vfile, pdata_section);
826
827
224
  paps.obj = vfile;
828
224
  paps.pdata_count = 0;
829
224
  bfd_map_over_sections (abfd, pex64_print_all_pdata_sections, &paps);
830
224
  return paps.pdata_count != 0;
831
237
}
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"