Coverage Report

Created: 2026-04-04 08:16

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.64k
#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
249
#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
234
{
88
234
  const struct external_pex64_runtime_function *ex_rf =
89
234
    (const struct external_pex64_runtime_function *) data;
90
234
  rf->rva_BeginAddress = bfd_get_32 (abfd, ex_rf->rva_BeginAddress);
91
234
  rf->rva_EndAddress = bfd_get_32 (abfd, ex_rf->rva_EndAddress);
92
234
  rf->rva_UnwindData =  bfd_get_32 (abfd, ex_rf->rva_UnwindData);
93
234
}
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
4
{
101
4
  struct external_pex64_unwind_info *ex_ui =
102
4
    (struct external_pex64_unwind_info *) data;
103
4
  bfd_byte *ex_dta = (bfd_byte *) data;
104
4
  bfd_byte *ex_dta_end = (bfd_byte *) data_end;
105
106
4
  memset (ui, 0, sizeof (struct pex64_unwind_info));
107
108
4
  if (ex_dta_end - ex_dta < 4)
109
0
    return false;
110
111
4
  ui->Version = PEX64_UWI_VERSION (ex_ui->Version_Flags);
112
4
  ui->Flags = PEX64_UWI_FLAGS (ex_ui->Version_Flags);
113
4
  ui->SizeOfPrologue = (bfd_vma) ex_ui->SizeOfPrologue;
114
4
  ui->CountOfCodes = (bfd_vma) ex_ui->CountOfCodes;
115
4
  ui->FrameRegister = PEX64_UWI_FRAMEREG (ex_ui->FrameRegisterOffset);
116
4
  ui->FrameOffset = PEX64_UWI_FRAMEOFF (ex_ui->FrameRegisterOffset);
117
4
  ui->sizeofUnwindCodes = PEX64_UWI_SIZEOF_UWCODE_ARRAY (ui->CountOfCodes);
118
4
  ui->SizeOfBlock = ui->sizeofUnwindCodes + 4;
119
4
  ui->rawUnwindCodes = ex_dta + 4;
120
4
  ui->rawUnwindCodesEnd = ex_dta_end;
121
122
4
  if ((size_t) (ex_dta_end - ex_dta) < ui->SizeOfBlock)
123
2
    return false;
124
2
  ex_dta += ui->SizeOfBlock;
125
126
2
  switch (ui->Flags)
127
2
    {
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
2
    default:
145
2
      return true;
146
2
    }
147
2
}
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
2
{
156
2
  unsigned int i;
157
2
  unsigned int tmp; /* At least 32 bits.  */
158
2
  int save_allowed;
159
160
2
  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
2
  save_allowed = true;
168
169
2
  i = 0;
170
171
2
  if ((size_t) (ui->rawUnwindCodesEnd - ui->rawUnwindCodes)
172
2
      < ui->CountOfCodes * 2)
173
0
    {
174
0
      fprintf (file, _("warning: corrupt unwind data\n"));
175
0
      return;
176
0
    }
177
178
2
  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
204
  for (; i < ui->CountOfCodes; i++)
210
202
    {
211
202
      const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
212
202
      unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
213
202
      int unexpected = false;
214
215
202
      fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
216
217
202
      switch (PEX64_UNWCODE_CODE (dta[1]))
218
202
  {
219
42
  case UWOP_PUSH_NONVOL:
220
42
    fprintf (file, "push %s", pex_regs[info]);
221
42
    break;
222
223
9
  case UWOP_ALLOC_LARGE:
224
9
    if (info == 0)
225
8
      {
226
8
        if (ui->rawUnwindCodesEnd - dta < 4)
227
0
    {
228
0
      fprintf (file, _("warning: corrupt unwind data\n"));
229
0
      return;
230
0
    }
231
8
        tmp = bfd_get_16 (abfd, dta + 2) * 8;
232
8
        i++;
233
8
      }
234
1
    else
235
1
      {
236
1
        if (ui->rawUnwindCodesEnd - dta < 6)
237
0
    {
238
0
      fprintf (file, _("warning: corrupt unwind data\n"));
239
0
      return;
240
0
    }
241
1
        tmp = bfd_get_32 (abfd, dta + 2);
242
1
        i += 2;
243
1
      }
244
9
    fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
245
9
    break;
246
247
5
  case UWOP_ALLOC_SMALL:
248
5
    fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
249
5
    break;
250
251
1
  case UWOP_SET_FPREG:
252
    /* According to the documentation, info field is unused.  */
253
1
    fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
254
1
       pex_regs[ui->FrameRegister],
255
1
       (unsigned int) ui->FrameOffset * 16, info);
256
1
    unexpected = ui->FrameRegister == 0;
257
1
    save_allowed = false;
258
1
    break;
259
260
2
  case UWOP_SAVE_NONVOL:
261
2
    if (ui->rawUnwindCodesEnd - dta < 4)
262
0
      {
263
0
        fprintf (file, _("warning: corrupt unwind data\n"));
264
0
        return;
265
0
      }
266
2
    tmp = bfd_get_16 (abfd, dta + 2) * 8;
267
2
    i++;
268
2
    fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
269
2
    unexpected = !save_allowed;
270
2
    break;
271
272
1
  case UWOP_SAVE_NONVOL_FAR:
273
1
    if (ui->rawUnwindCodesEnd - dta < 6)
274
0
      {
275
0
        fprintf (file, _("warning: corrupt unwind data\n"));
276
0
        return;
277
0
      }
278
1
    tmp = bfd_get_32 (abfd, dta + 2);
279
1
    i += 2;
280
1
    fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
281
1
    unexpected = !save_allowed;
282
1
    break;
283
284
3
  case UWOP_SAVE_XMM:
285
3
    if (ui->Version == 1)
286
3
      {
287
3
        if (ui->rawUnwindCodesEnd - dta < 4)
288
0
    {
289
0
      fprintf (file, _("warning: corrupt unwind data\n"));
290
0
      return;
291
0
    }
292
3
        tmp = bfd_get_16 (abfd, dta + 2) * 8;
293
3
        i++;
294
3
        fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
295
3
        unexpected = !save_allowed;
296
3
      }
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
3
    break;
303
304
32
  case UWOP_SAVE_XMM_FAR:
305
32
    if (ui->rawUnwindCodesEnd - dta < 6)
306
0
      {
307
0
        fprintf (file, _("warning: corrupt unwind data\n"));
308
0
        return;
309
0
      }
310
32
    tmp = bfd_get_32 (abfd, dta + 2) * 8;
311
32
    i += 2;
312
32
    fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
313
32
    unexpected = !save_allowed;
314
32
    break;
315
316
3
  case UWOP_SAVE_XMM128:
317
3
    if (ui->rawUnwindCodesEnd - dta < 4)
318
0
      {
319
0
        fprintf (file, _("warning: corrupt unwind data\n"));
320
0
        return;
321
0
      }
322
3
    tmp = bfd_get_16 (abfd, dta + 2) * 16;
323
3
    i++;
324
3
    fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
325
3
    unexpected = !save_allowed;
326
3
    break;
327
328
4
  case UWOP_SAVE_XMM128_FAR:
329
4
    if (ui->rawUnwindCodesEnd - dta < 6)
330
0
      {
331
0
        fprintf (file, _("warning: corrupt unwind data\n"));
332
0
        return;
333
0
      }
334
4
    tmp = bfd_get_32 (abfd, dta + 2) * 16;
335
4
    i += 2;
336
4
    fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
337
4
    unexpected = !save_allowed;
338
4
    break;
339
340
1
  case UWOP_PUSH_MACHFRAME:
341
1
    fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
342
1
    if (info == 0)
343
0
      fprintf (file, ")");
344
1
    else if (info == 1)
345
1
      fprintf (file, ",ErrorCode)");
346
0
    else
347
0
      fprintf (file, ", unknown(%u))", info);
348
1
    break;
349
350
99
  default:
351
    /* PR 17512: file: 2245-7442-0.004.  */
352
99
    fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
353
99
    break;
354
202
  }
355
356
202
      if (unexpected)
357
33
  fprintf (file, " [Unexpected!]");
358
202
      fputc ('\n', file);
359
202
    }
360
2
}
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
8
{
367
8
  asection *section = bfd_get_section_by_name (abfd, sec_name);
368
8
  bfd_vma vsize;
369
8
  bfd_size_type datasize = 0;
370
371
8
  if (section == NULL
372
2
      || coff_section_data (abfd, section) == NULL
373
2
      || pei_section_data (abfd, section) == NULL)
374
6
    return NULL;
375
2
  vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
376
2
  datasize = section->size;
377
2
  if (!datasize || vsize > addr || (vsize + datasize) < addr)
378
0
    return NULL;
379
2
  return section;
380
2
}
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
4
{
391
4
  bfd_vma vaddr;
392
4
  bfd_vma end_addr;
393
4
  bfd_vma addr = rf->rva_UnwindData;
394
4
  bfd_size_type sec_size = xdata_section->rawsize > 0 ? xdata_section->rawsize : xdata_section->size;
395
4
  struct pex64_unwind_info ui;
396
397
4
  vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
398
4
  addr -= vaddr;
399
400
  /* PR 17512: file: 2245-7442-0.004.  */
401
4
  if (addr >= sec_size)
402
0
    {
403
0
      fprintf (file, _("warning: xdata section corrupt\n"));
404
0
      return;
405
0
    }
406
407
4
  if (endx)
408
2
    {
409
2
      end_addr = endx[0] - vaddr;
410
      /* PR 17512: file: 2245-7442-0.004.  */
411
2
      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
2
    }
417
2
  else
418
2
    end_addr = sec_size;
419
420
4
  if (! pex64_get_unwind_info (abfd, &ui, xdata + addr, xdata + end_addr))
421
2
    {
422
2
      fprintf (file, _("warning: xdata section corrupt\n"));
423
2
      return;
424
2
    }
425
426
2
  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
2
  fprintf (file, "\tVersion: %d, Flags: ", ui.Version);
445
2
  switch (ui.Flags)
446
2
    {
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
2
    default:
464
2
      fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
465
2
      break;
466
2
    }
467
2
  fputc ('\n', file);
468
2
  fprintf (file, "\tNbr codes: %u, ", (unsigned int) ui.CountOfCodes);
469
2
  fprintf (file, "Prologue size: 0x%02x, Frame offset: 0x%x, ",
470
2
     (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
471
2
  fprintf (file, "Frame reg: %s\n",
472
2
     ui.FrameRegister == 0 ? "none"
473
2
     : pex_regs[(unsigned int) ui.FrameRegister]);
474
475
  /* PR 17512: file: 2245-7442-0.004.  */
476
2
  if (ui.CountOfCodes * 2 + ui.rawUnwindCodes > xdata + xdata_section->size)
477
0
    fprintf (file, _("Too many unwind codes (%ld)\n"), (long) ui.CountOfCodes);
478
2
  else
479
2
    pex64_xdata_print_uwd_codes (file, abfd, &ui, rf);
480
481
2
  switch (ui.Flags)
482
2
    {
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
2
    }
496
497
  /* Now we need end of this xdata block.  */
498
2
  addr += ui.SizeOfBlock;
499
2
  if (addr < end_addr)
500
2
    {
501
2
      unsigned int i;
502
2
      fprintf (file,"\tUser data:\n");
503
498
      for (i = 0; addr < end_addr; addr += 1, i++)
504
496
  {
505
496
    if ((i & 15) == 0)
506
32
      fprintf (file, "\t  %03x:", i);
507
496
    fprintf (file, " %02x", xdata[addr]);
508
496
    if ((i & 15) == 15)
509
30
      fprintf (file, "\n");
510
496
  }
511
2
      if ((i & 15) != 0)
512
2
  fprintf (file, "\n");
513
2
    }
514
2
}
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
12
{
522
12
  const bfd_vma *lp = (const bfd_vma *) l;
523
12
  const bfd_vma *rp = (const bfd_vma *) r;
524
525
12
  if (*lp == *rp)
526
4
    return 0;
527
8
  return (*lp < *rp ? -1 : 1);
528
12
}
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
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
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
2
    {
578
2
      stop = datasize;
579
2
      virt_size_is_zero = true;
580
2
    }
581
13
  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
12
    goto done;
601
602
  /* Table of xdata entries.  */
603
3
  xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
604
3
  xdata_arr_cnt = 0;
605
606
3
  if (strcmp (abfd->xvec->name, "pei-x86-64") == 0)
607
0
    imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
608
3
  else
609
3
    imagebase = 0;
610
611
228
  for (i = 0; i < stop; i += onaline)
612
228
    {
613
228
      struct pex64_runtime_function rf;
614
615
228
      if (i + PDATA_ROW_SIZE > stop)
616
0
  break;
617
618
228
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
619
620
228
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
621
8
    && rf.rva_UnwindData == 0)
622
  /* We are probably into the padding of the section now.  */
623
3
  break;
624
225
      fprintf (file, " %016" PRIx64, i + pdata_section->vma);
625
225
      fprintf (file, ":\t%016" PRIx64, imagebase + rf.rva_BeginAddress);
626
225
      fprintf (file, " %016" PRIx64, imagebase + rf.rva_EndAddress);
627
225
      fprintf (file, " %016" PRIx64 "\n", imagebase + rf.rva_UnwindData);
628
225
      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
225
      prev_beginaddress = rf.rva_BeginAddress;
635
      /* Now we check for negative addresses.  */
636
225
      if ((prev_beginaddress & 0x80000000) != 0)
637
42
  {
638
42
    seen_error = 1;
639
42
    fprintf (file, "  has negative begin address\n");
640
42
  }
641
225
      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
225
      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
168
      else if ((rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
652
51
    || virt_size_is_zero)
653
117
  xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
654
225
    }
655
656
3
  if (seen_error)
657
1
    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
0
    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
697
  /* Transfer xdata section into xdata array.  */
698
2
  if (!xdata_section
699
2
      || (xdata_section->flags & SEC_HAS_CONTENTS) == 0
700
2
      || !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
2
  prev_unwinddata_rva = (bfd_vma) -1;
706
707
  /* Do dump of pdata related xdata.  */
708
6
  for (i = 0; i < stop; i += onaline)
709
6
    {
710
6
      struct pex64_runtime_function rf;
711
712
6
      if (i + PDATA_ROW_SIZE > stop)
713
0
  break;
714
715
6
      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
716
717
6
      if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
718
2
    && rf.rva_UnwindData == 0)
719
  /* We are probably into the padding of the section now.  */
720
2
  break;
721
4
      if (i == 0)
722
2
  fprintf (file, _("\nDump of %s\n"), xdata_section->name);
723
724
4
      fprintf (file, " %016" PRIx64, rf.rva_UnwindData + imagebase);
725
726
4
      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
4
      else
734
4
  prev_unwinddata_rva = rf.rva_UnwindData;
735
736
4
      fprintf (file, " (rva: %08x): %016" PRIx64 " - %016" PRIx64 "\n",
737
4
         (unsigned int) rf.rva_UnwindData,
738
4
         rf.rva_BeginAddress + imagebase,
739
4
         rf.rva_EndAddress + imagebase);
740
741
4
      if (rf.rva_UnwindData != 0 || virt_size_is_zero)
742
4
  {
743
4
    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
4
    else
765
4
      {
766
4
        bfd_vma *p;
767
768
        /* Search for the current entry in the sorted array.  */
769
4
        p = (bfd_vma *)
770
4
      bsearch (&rf.rva_UnwindData, xdata_arr,
771
4
         (size_t) xdata_arr_cnt, sizeof (bfd_vma),
772
4
         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
8
        while (p[0] <= rf.rva_UnwindData)
778
4
    ++p;
779
780
4
        if (p[0] == ~((bfd_vma) 0))
781
2
    p = NULL;
782
783
4
        pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
784
4
      }
785
4
  }
786
4
    }
787
788
15
 done:
789
15
  free (pdata);
790
15
  free (xdata_arr);
791
15
  free (xdata);
792
793
15
  return true;
794
2
}
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.01k
{
810
4.01k
  struct pex64_paps *paps = arg;
811
4.01k
  if (startswith (pdata->name, ".pdata"))
812
1
    {
813
1
      if (pex64_bfd_print_pdata_section (abfd, paps->obj, pdata))
814
1
  paps->pdata_count++;
815
1
    }
816
4.01k
}
817
818
bool
819
pex64_bfd_print_pdata (bfd *abfd, void *vfile)
820
208
{
821
208
  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
822
208
  struct pex64_paps paps;
823
824
208
  if (pdata_section)
825
14
    return pex64_bfd_print_pdata_section (abfd, vfile, pdata_section);
826
827
194
  paps.obj = vfile;
828
194
  paps.pdata_count = 0;
829
194
  bfd_map_over_sections (abfd, pex64_print_all_pdata_sections, &paps);
830
194
  return paps.pdata_count != 0;
831
208
}
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"