Coverage Report

Created: 2025-06-24 06:45

/src/binutils-gdb/bfd/verilog.c
Line
Count
Source (jump to first uncovered line)
1
/* BFD back-end for verilog hex memory dump files.
2
   Copyright (C) 2009-2025 Free Software Foundation, Inc.
3
   Written by Anthony Green <green@moxielogic.com>
4
5
   This file is part of BFD, the Binary File Descriptor library.
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program; if not, write to the Free Software
19
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
22
23
/* SUBSECTION
24
  Verilog hex memory file handling
25
26
   DESCRIPTION
27
28
  Verilog hex memory files cannot hold anything but addresses
29
  and data, so that's all that we implement.
30
31
  The syntax of the text file is described in the IEEE standard
32
  for Verilog.  Briefly, the file contains two types of tokens:
33
  data and optional addresses.  The tokens are separated by
34
  whitespace and comments.  Comments may be single line or
35
  multiline, using syntax similar to C++.  Addresses are
36
  specified by a leading "at" character (@) and are always
37
  hexadecimal strings.  Data and addresses may contain
38
  underscore (_) characters.
39
40
  If no address is specified, the data is assumed to start at
41
  address 0.  Similarly, if data exists before the first
42
  specified address, then that data is assumed to start at
43
  address 0.
44
45
46
   EXAMPLE
47
  @1000
48
  01 ae 3f 45 12
49
50
   DESCRIPTION
51
  @1000 specifies the starting address for the memory data.
52
  The following characters describe the 5 bytes at 0x1000.  */
53
54
55
#include "sysdep.h"
56
#include "bfd.h"
57
#include "libbfd.h"
58
#include "libiberty.h"
59
#include "safe-ctype.h"
60
61
/* Modified by obcopy.c
62
   Data width in bytes.  */
63
unsigned int VerilogDataWidth = 1;
64
65
/* Modified by obcopy.c
66
   Data endianness.  */
67
enum bfd_endian VerilogDataEndianness = BFD_ENDIAN_UNKNOWN;
68
69
/* Macros for converting between hex and binary.  */
70
71
static const char digs[] = "0123456789ABCDEF";
72
73
#define NIBBLE(x)    hex_value (x)
74
#define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1]))
75
#define TOHEX(d, x) \
76
0
  d[1] = digs[(x) & 0xf]; \
77
0
  d[0] = digs[((x) >> 4) & 0xf];
78
79
/* When writing a verilog memory dump file, we write them in the order
80
   in which they appear in memory. This structure is used to hold them
81
   in memory.  */
82
83
struct verilog_data_list_struct
84
{
85
  struct verilog_data_list_struct *next;
86
  bfd_byte * data;
87
  bfd_vma where;
88
  bfd_size_type size;
89
};
90
91
typedef struct verilog_data_list_struct verilog_data_list_type;
92
93
/* The verilog tdata information.  */
94
95
typedef struct verilog_data_struct
96
{
97
  verilog_data_list_type *head;
98
  verilog_data_list_type *tail;
99
}
100
tdata_type;
101
102
static bool
103
verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach)
104
0
{
105
0
  if (arch != bfd_arch_unknown)
106
0
    return bfd_default_set_arch_mach (abfd, arch, mach);
107
108
0
  abfd->arch_info = & bfd_default_arch_struct;
109
0
  return true;
110
0
}
111
112
/* We have to save up all the output for a splurge before output.  */
113
114
static bool
115
verilog_set_section_contents (bfd *abfd,
116
            sec_ptr section,
117
            const void * location,
118
            file_ptr offset,
119
            bfd_size_type bytes_to_do)
120
0
{
121
0
  tdata_type *tdata = abfd->tdata.verilog_data;
122
0
  verilog_data_list_type *entry;
123
124
0
  entry = (verilog_data_list_type *) bfd_alloc (abfd, sizeof (* entry));
125
0
  if (entry == NULL)
126
0
    return false;
127
128
0
  if (bytes_to_do
129
0
      && (section->flags & SEC_ALLOC)
130
0
      && (section->flags & SEC_LOAD))
131
0
    {
132
0
      bfd_byte *data;
133
134
0
      data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do);
135
0
      if (data == NULL)
136
0
  return false;
137
0
      memcpy ((void *) data, location, (size_t) bytes_to_do);
138
139
0
      entry->data = data;
140
0
      entry->where = section->lma + offset;
141
0
      entry->size = bytes_to_do;
142
143
      /* Sort the records by address.  Optimize for the common case of
144
   adding a record to the end of the list.  */
145
0
      if (tdata->tail != NULL
146
0
    && entry->where >= tdata->tail->where)
147
0
  {
148
0
    tdata->tail->next = entry;
149
0
    entry->next = NULL;
150
0
    tdata->tail = entry;
151
0
  }
152
0
      else
153
0
  {
154
0
    verilog_data_list_type **look;
155
156
0
    for (look = &tdata->head;
157
0
         *look != NULL && (*look)->where < entry->where;
158
0
         look = &(*look)->next)
159
0
      ;
160
0
    entry->next = *look;
161
0
    *look = entry;
162
0
    if (entry->next == NULL)
163
0
      tdata->tail = entry;
164
0
  }
165
0
    }
166
0
  return true;
167
0
}
168
169
static bool
170
verilog_write_address (bfd *abfd, bfd_vma address)
171
0
{
172
0
  char buffer[20];
173
0
  char *dst = buffer;
174
0
  bfd_size_type wrlen;
175
176
  /* Write the address.  */
177
0
  *dst++ = '@';
178
0
#ifdef BFD64
179
0
  if (address >= (bfd_vma)1 << 32)
180
0
    {
181
0
      TOHEX (dst, (address >> 56));
182
0
      dst += 2;
183
0
      TOHEX (dst, (address >> 48));
184
0
      dst += 2;
185
0
      TOHEX (dst, (address >> 40));
186
0
      dst += 2;
187
0
      TOHEX (dst, (address >> 32));
188
0
      dst += 2;
189
0
    }
190
0
#endif
191
0
  TOHEX (dst, (address >> 24));
192
0
  dst += 2;
193
0
  TOHEX (dst, (address >> 16));
194
0
  dst += 2;
195
0
  TOHEX (dst, (address >> 8));
196
0
  dst += 2;
197
0
  TOHEX (dst, (address));
198
0
  dst += 2;
199
0
  *dst++ = '\r';
200
0
  *dst++ = '\n';
201
0
  wrlen = dst - buffer;
202
203
0
  return bfd_write (buffer, wrlen, abfd) == wrlen;
204
0
}
205
206
/* Write a record of type, of the supplied number of bytes. The
207
   supplied bytes and length don't have a checksum.  That's worked
208
   out here.  */
209
210
static bool
211
verilog_write_record (bfd *abfd,
212
          const bfd_byte *data,
213
          const bfd_byte *end)
214
0
{
215
0
  char buffer[52];
216
0
  const bfd_byte *src = data;
217
0
  char *dst = buffer;
218
0
  bfd_size_type wrlen;
219
220
  /* Paranoia - check that we will not overflow "buffer".  */
221
0
  if (((end - data) * 2) /* Number of hex characters we want to emit.  */
222
0
      + ((end - data) / VerilogDataWidth) /* Number of spaces we want to emit.  */
223
0
      + 2 /* The carriage return & line feed characters.  */
224
0
      > (long) sizeof (buffer))
225
0
    {
226
      /* FIXME: Should we generate an error message ?  */
227
0
      return false;
228
0
    }
229
230
  /* Write the data.
231
     FIXME: Under some circumstances we can emit a space at the end of
232
     the line.  This is not really necessary, but catching these cases
233
     would make the code more complicated.  */
234
0
  if (VerilogDataWidth == 1)
235
0
    {
236
0
      for (src = data; src < end;)
237
0
  {
238
0
    TOHEX (dst, *src);
239
0
    dst += 2;
240
0
    src ++;
241
0
    if (src < end)
242
0
      *dst++ = ' ';
243
0
  }
244
0
    }
245
0
  else if ((VerilogDataEndianness == BFD_ENDIAN_UNKNOWN && bfd_little_endian (abfd)) /* FIXME: Can this happen ?  */
246
0
     || (VerilogDataEndianness == BFD_ENDIAN_LITTLE))
247
0
    {
248
      /* If the input byte stream contains:
249
     05 04 03 02 01 00
250
   and VerilogDataWidth is 4 then we want to emit:
251
           02030405 0001  */
252
0
      int i;
253
254
0
      for (src = data; src < (end - VerilogDataWidth); src += VerilogDataWidth)
255
0
  {
256
0
    for (i = VerilogDataWidth - 1; i >= 0; i--)
257
0
      {
258
0
        TOHEX (dst, src[i]);
259
0
        dst += 2;
260
0
      }
261
0
    *dst++ = ' ';
262
0
  }
263
264
      /* Emit any remaining bytes.  Be careful not to read beyond "end".  */
265
0
      while (end > src)
266
0
  {
267
0
    -- end;
268
0
    TOHEX (dst, *end);
269
0
    dst += 2;
270
0
  }
271
272
      /* FIXME: Should padding bytes be inserted here ?  */
273
0
    }
274
0
  else /* Big endian output.  */
275
0
    {
276
0
      for (src = data; src < end;)
277
0
  {
278
0
    TOHEX (dst, *src);
279
0
    dst += 2;
280
0
    ++ src;
281
0
    if ((src - data) % VerilogDataWidth == 0)
282
0
      *dst++ = ' ';
283
0
  }
284
      /* FIXME: Should padding bytes be inserted here ?  */
285
0
    }
286
287
0
  *dst++ = '\r';
288
0
  *dst++ = '\n';
289
0
  wrlen = dst - buffer;
290
291
0
  return bfd_write (buffer, wrlen, abfd) == wrlen;
292
0
}
293
294
static bool
295
verilog_write_section (bfd *abfd,
296
           tdata_type *tdata ATTRIBUTE_UNUSED,
297
           verilog_data_list_type *list)
298
0
{
299
0
  unsigned int octets_written = 0;
300
0
  bfd_byte *location = list->data;
301
302
  /* Insist that the starting address is a multiple of the data width.  */
303
0
  if (list->where % VerilogDataWidth)
304
0
    {
305
0
      bfd_set_error (bfd_error_invalid_operation);
306
0
      return false;
307
0
    }
308
309
0
  verilog_write_address (abfd, list->where / VerilogDataWidth);
310
0
  while (octets_written < list->size)
311
0
    {
312
0
      unsigned int octets_this_chunk = list->size - octets_written;
313
314
0
      if (octets_this_chunk > 16)
315
0
  octets_this_chunk = 16;
316
317
0
      if (! verilog_write_record (abfd,
318
0
          location,
319
0
          location + octets_this_chunk))
320
0
  return false;
321
322
0
      octets_written += octets_this_chunk;
323
0
      location += octets_this_chunk;
324
0
    }
325
326
0
  return true;
327
0
}
328
329
static bool
330
verilog_write_object_contents (bfd *abfd)
331
0
{
332
0
  tdata_type *tdata = abfd->tdata.verilog_data;
333
0
  verilog_data_list_type *list;
334
335
  /* Now wander though all the sections provided and output them.  */
336
0
  list = tdata->head;
337
338
0
  while (list != (verilog_data_list_type *) NULL)
339
0
    {
340
0
      if (! verilog_write_section (abfd, tdata, list))
341
0
  return false;
342
0
      list = list->next;
343
0
    }
344
0
  return true;
345
0
}
346
347
/* Initialize by filling in the hex conversion array.  */
348
349
static void
350
verilog_init (void)
351
0
{
352
0
  static bool inited = false;
353
354
0
  if (! inited)
355
0
    {
356
0
      inited = true;
357
0
      hex_init ();
358
0
    }
359
0
}
360
361
/* Set up the verilog tdata information.  */
362
363
static bool
364
verilog_mkobject (bfd *abfd)
365
0
{
366
0
  tdata_type *tdata;
367
368
0
  verilog_init ();
369
370
0
  tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
371
0
  if (tdata == NULL)
372
0
    return false;
373
374
0
  abfd->tdata.verilog_data = tdata;
375
0
  tdata->head = NULL;
376
0
  tdata->tail = NULL;
377
378
0
  return true;
379
0
}
380
381
const bfd_target verilog_vec =
382
{
383
  "verilog",      /* Name.  */
384
  bfd_target_verilog_flavour,
385
  BFD_ENDIAN_UNKNOWN,   /* Target byte order.  */
386
  BFD_ENDIAN_UNKNOWN,   /* Target headers byte order.  */
387
  EXEC_P,     /* Object flags.  */
388
  (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
389
   | SEC_ALLOC | SEC_LOAD), /* Section flags.  */
390
  0,        /* Leading underscore.  */
391
  ' ',        /* AR_pad_char.  */
392
  16,       /* AR_max_namelen.  */
393
  0,        /* match priority.  */
394
  TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
395
  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
396
  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
397
  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data.  */
398
  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
399
  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
400
  bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs.  */
401
402
  {
403
    _bfd_dummy_target,
404
    _bfd_dummy_target,
405
    _bfd_dummy_target,
406
    _bfd_dummy_target,
407
  },
408
  {
409
    _bfd_bool_bfd_false_error,
410
    verilog_mkobject,
411
    _bfd_bool_bfd_false_error,
412
    _bfd_bool_bfd_false_error,
413
  },
414
  {       /* bfd_write_contents.  */
415
    _bfd_bool_bfd_false_error,
416
    verilog_write_object_contents,
417
    _bfd_bool_bfd_false_error,
418
    _bfd_bool_bfd_false_error,
419
  },
420
421
  BFD_JUMP_TABLE_GENERIC (_bfd_generic),
422
  BFD_JUMP_TABLE_COPY (_bfd_generic),
423
  BFD_JUMP_TABLE_CORE (_bfd_nocore),
424
  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
425
  BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
426
  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
427
  BFD_JUMP_TABLE_WRITE (verilog),
428
  BFD_JUMP_TABLE_LINK (_bfd_nolink),
429
  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
430
431
  NULL,
432
433
  NULL
434
};