X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Fwasm-module.c;h=9735ebeabca8be02e5ad10ee8aafbc815f46dbba;hb=3da4c6449b1ce57accfb1b9fa8415ad1cf42039b;hp=3deaf42bac47b7ff5574e9c5b75efe043f5a0a63;hpb=2d5d5a8f0a8b5a03454bf168b7fa7024bb1ebbd8;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/wasm-module.c b/bfd/wasm-module.c index 3deaf42bac..9735ebeabc 100644 --- a/bfd/wasm-module.c +++ b/bfd/wasm-module.c @@ -1,5 +1,5 @@ /* BFD back-end for WebAssembly modules. - Copyright (C) 2017-2018 Free Software Foundation, Inc. + Copyright (C) 2017-2021 Free Software Foundation, Inc. Based on srec.c, mmo.c, and binary.c @@ -26,13 +26,16 @@ https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md. */ #include "sysdep.h" -#include "alloca-conf.h" #include "bfd.h" -#include #include "libiberty.h" #include "libbfd.h" #include "wasm-module.h" +#include +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + typedef struct { asymbol * symbols; @@ -102,27 +105,44 @@ wasm_section_name_to_code (const char *name) incomplete numbers). SIGN means interpret the number as SLEB128. */ static bfd_vma -wasm_read_leb128 (bfd * abfd, - bfd_boolean * error_return, - unsigned int * length_return, - bfd_boolean sign) +wasm_read_leb128 (bfd *abfd, + bool *error_return, + unsigned int *length_return, + bool sign) { bfd_vma result = 0; unsigned int num_read = 0; unsigned int shift = 0; unsigned char byte = 0; - bfd_boolean success = FALSE; + unsigned char lost, mask; + int status = 1; while (bfd_bread (&byte, 1, abfd) == 1) { num_read++; - result |= ((bfd_vma) (byte & 0x7f)) << shift; + if (shift < CHAR_BIT * sizeof (result)) + { + result |= ((bfd_vma) (byte & 0x7f)) << shift; + /* These bits overflowed. */ + lost = byte ^ (result >> shift); + /* And this is the mask of possible overflow bits. */ + mask = 0x7f ^ ((bfd_vma) 0x7f << shift >> shift); + shift += 7; + } + else + { + lost = byte; + mask = 0x7f; + } + if ((lost & mask) != (sign && (bfd_signed_vma) result < 0 ? mask : 0)) + status |= 2; - shift += 7; if ((byte & 0x80) == 0) { - success = TRUE; + status &= ~1; + if (sign && shift < CHAR_BIT * sizeof (result) && (byte & 0x40)) + result |= -((bfd_vma) 1 << shift); break; } } @@ -130,10 +150,7 @@ wasm_read_leb128 (bfd * abfd, if (length_return != NULL) *length_return = num_read; if (error_return != NULL) - *error_return = ! success; - - if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -((bfd_vma) 1 << shift); + *error_return = status != 0; return result; } @@ -141,7 +158,7 @@ wasm_read_leb128 (bfd * abfd, /* Encode an integer V as LEB128 and write it to ABFD, return TRUE on success. */ -static bfd_boolean +static bool wasm_write_uleb128 (bfd *abfd, bfd_vma v) { do @@ -153,11 +170,11 @@ wasm_write_uleb128 (bfd *abfd, bfd_vma v) c |= 0x80; if (bfd_bwrite (&c, 1, abfd) != 1) - return FALSE; + return false; } while (v); - return TRUE; + return true; } /* Read the LEB128 integer at P, saving it to X; at end of buffer, @@ -165,37 +182,34 @@ wasm_write_uleb128 (bfd *abfd, bfd_vma v) #define READ_LEB128(x, p, end) \ do \ { \ - unsigned int length_read; \ - (x) = _bfd_safe_read_leb128 (abfd, (p), &length_read, \ - FALSE, (end)); \ - (p) += length_read; \ - if (length_read == 0) \ + if ((p) >= (end)) \ goto error_return; \ + (x) = _bfd_safe_read_leb128 (abfd, &(p), false, (end)); \ } \ while (0) /* Verify the magic number at the beginning of a WebAssembly module ABFD, setting ERRORPTR if there's a mismatch. */ -static bfd_boolean -wasm_read_magic (bfd *abfd, bfd_boolean *errorptr) +static bool +wasm_read_magic (bfd *abfd, bool *errorptr) { bfd_byte magic_const[SIZEOF_WASM_MAGIC] = WASM_MAGIC; bfd_byte magic[SIZEOF_WASM_MAGIC]; if (bfd_bread (magic, sizeof (magic), abfd) == sizeof (magic) && memcmp (magic, magic_const, sizeof (magic)) == 0) - return TRUE; + return true; - *errorptr = TRUE; - return FALSE; + *errorptr = true; + return false; } /* Read the version number from ABFD, returning TRUE if it's a supported version. Set ERRORPTR otherwise. */ -static bfd_boolean -wasm_read_version (bfd *abfd, bfd_boolean *errorptr) +static bool +wasm_read_version (bfd *abfd, bool *errorptr) { bfd_byte vers_const[SIZEOF_WASM_VERSION] = WASM_VERSION; bfd_byte vers[SIZEOF_WASM_VERSION]; @@ -204,31 +218,31 @@ wasm_read_version (bfd *abfd, bfd_boolean *errorptr) /* Don't attempt to parse newer versions, which are likely to require code changes. */ && memcmp (vers, vers_const, sizeof (vers)) == 0) - return TRUE; + return true; - *errorptr = TRUE; - return FALSE; + *errorptr = true; + return false; } /* Read the WebAssembly header (magic number plus version number) from ABFD, setting ERRORPTR to TRUE if there is a mismatch. */ -static bfd_boolean -wasm_read_header (bfd *abfd, bfd_boolean *errorptr) +static bool +wasm_read_header (bfd *abfd, bool *errorptr) { if (! wasm_read_magic (abfd, errorptr)) - return FALSE; + return false; if (! wasm_read_version (abfd, errorptr)) - return FALSE; + return false; - return TRUE; + return true; } /* Scan the "function" subsection of the "name" section ASECT in the wasm module ABFD. Create symbols. Return TRUE on success. */ -static bfd_boolean +static bool wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) { bfd_byte *p; @@ -238,18 +252,13 @@ wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) tdata_type *tdata = abfd->tdata.any; asymbol *symbols = NULL; sec_ptr space_function_index; - - if (! asect) - return FALSE; - - if (strcmp (asect->name, WASM_NAME_SECTION) != 0) - return FALSE; + size_t amt; p = asect->contents; end = asect->contents + asect->size; - if (! p) - return FALSE; + if (!p) + return false; while (p < end) { @@ -261,49 +270,53 @@ wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) it has to be a single byte in the 0 - 127 range. If it isn't, the spec must have changed underneath us, so give up. */ if (subsection_code & 0x80) - return FALSE; + return false; READ_LEB128 (payload_size, p, end); - if (p > p + payload_size) - return FALSE; + if (payload_size > (size_t) (end - p)) + return false; p += payload_size; } if (p >= end) - return FALSE; + return false; READ_LEB128 (payload_size, p, end); - if (p > p + payload_size) - return FALSE; - - if (p + payload_size > end) - return FALSE; + if (payload_size > (size_t) (end - p)) + return false; end = p + payload_size; READ_LEB128 (symcount, p, end); /* Sanity check: each symbol has at least two bytes. */ - if (symcount > payload_size/2) - return FALSE; + if (symcount > payload_size / 2) + return false; tdata->symcount = symcount; - space_function_index = bfd_make_section_with_flags - (abfd, WASM_SECTION_FUNCTION_INDEX, SEC_READONLY | SEC_CODE); + space_function_index + = bfd_make_section_with_flags (abfd, WASM_SECTION_FUNCTION_INDEX, + SEC_READONLY | SEC_CODE); - if (! space_function_index) - space_function_index = bfd_get_section_by_name (abfd, WASM_SECTION_FUNCTION_INDEX); + if (!space_function_index) + space_function_index + = bfd_get_section_by_name (abfd, WASM_SECTION_FUNCTION_INDEX); - if (! space_function_index) - return FALSE; + if (!space_function_index) + return false; - symbols = bfd_zalloc (abfd, tdata->symcount * sizeof (asymbol)); - if (! symbols) - return FALSE; + if (_bfd_mul_overflow (tdata->symcount, sizeof (asymbol), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + return false; + } + symbols = bfd_alloc (abfd, amt); + if (!symbols) + return false; for (symcount = 0; p < end && symcount < tdata->symcount; symcount++) { @@ -315,14 +328,15 @@ wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) READ_LEB128 (idx, p, end); READ_LEB128 (len, p, end); - if (p + len < p || p + len > end) + if (len > (size_t) (end - p)) goto error_return; - name = bfd_zalloc (abfd, len + 1); - if (! name) + name = bfd_alloc (abfd, len + 1); + if (!name) goto error_return; memcpy (name, p, len); + name[len] = 0; p += len; sym = &symbols[symcount]; @@ -340,27 +354,25 @@ wasm_scan_name_function_section (bfd *abfd, sec_ptr asect) tdata->symbols = symbols; abfd->symcount = symcount; - return TRUE; + return true; error_return: - while (symcount) - bfd_release (abfd, (void *)symbols[--symcount].name); bfd_release (abfd, symbols); - return FALSE; + return false; } /* Read a byte from ABFD and return it, or EOF for EOF or error. Set ERRORPTR on non-EOF error. */ static int -wasm_read_byte (bfd *abfd, bfd_boolean *errorptr) +wasm_read_byte (bfd *abfd, bool *errorptr) { bfd_byte byte; if (bfd_bread (&byte, (bfd_size_type) 1, abfd) != 1) { if (bfd_get_error () != bfd_error_file_truncated) - *errorptr = TRUE; + *errorptr = true; return EOF; } @@ -370,22 +382,21 @@ wasm_read_byte (bfd *abfd, bfd_boolean *errorptr) /* Scan the wasm module ABFD, creating sections and symbols. Return TRUE on success. */ -static bfd_boolean +static bool wasm_scan (bfd *abfd) { - bfd_boolean error = FALSE; + bool error = false; /* Fake VMAs for now. Choose 0x80000000 as base to avoid clashes with actual data addresses. */ bfd_vma vma = 0x80000000; int section_code; unsigned int bytes_read; - char *name = NULL; asection *bfdsec; if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) goto error_return; - if (! wasm_read_header (abfd, &error)) + if (!wasm_read_header (abfd, &error)) goto error_return; while ((section_code = wasm_read_byte (abfd, &error)) != EOF) @@ -394,69 +405,66 @@ wasm_scan (bfd *abfd) { const char *sname = wasm_section_code_to_name (section_code); - if (! sname) + if (!sname) goto error_return; - name = strdup (sname); - bfdsec = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); + bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, + SEC_HAS_CONTENTS); if (bfdsec == NULL) goto error_return; - name = NULL; - bfdsec->vma = vma; - bfdsec->lma = vma; - bfdsec->size = wasm_read_leb128 (abfd, &error, &bytes_read, FALSE); + bfdsec->size = wasm_read_leb128 (abfd, &error, &bytes_read, false); if (error) goto error_return; - bfdsec->filepos = bfd_tell (abfd); - bfdsec->alignment_power = 0; } else { bfd_vma payload_len; - file_ptr section_start; bfd_vma namelen; + char *name; char *prefix = WASM_SECTION_PREFIX; - char *p; - int ret; + size_t prefixlen = strlen (prefix); + ufile_ptr filesize; - payload_len = wasm_read_leb128 (abfd, &error, &bytes_read, FALSE); + payload_len = wasm_read_leb128 (abfd, &error, &bytes_read, false); if (error) goto error_return; - section_start = bfd_tell (abfd); - namelen = wasm_read_leb128 (abfd, &error, &bytes_read, FALSE); - if (error || namelen > payload_len) - goto error_return; - name = bfd_zmalloc (namelen + strlen (prefix) + 1); - if (! name) + namelen = wasm_read_leb128 (abfd, &error, &bytes_read, false); + if (error || bytes_read > payload_len + || namelen > payload_len - bytes_read) goto error_return; - p = name; - ret = sprintf (p, "%s", prefix); - if (ret < 0 || (bfd_vma) ret != strlen (prefix)) + payload_len -= namelen + bytes_read; + filesize = bfd_get_file_size (abfd); + if (filesize != 0 && namelen > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return false; + } + name = bfd_alloc (abfd, namelen + prefixlen + 1); + if (!name) goto error_return; - p += ret; - if (bfd_bread (p, namelen, abfd) != namelen) + memcpy (name, prefix, prefixlen); + if (bfd_bread (name + prefixlen, namelen, abfd) != namelen) goto error_return; + name[prefixlen + namelen] = 0; - bfdsec = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); + bfdsec = bfd_make_section_anyway_with_flags (abfd, name, + SEC_HAS_CONTENTS); if (bfdsec == NULL) goto error_return; - name = NULL; - bfdsec->vma = vma; - bfdsec->lma = vma; - bfdsec->filepos = bfd_tell (abfd); - bfdsec->size = section_start + payload_len - bfdsec->filepos; - bfdsec->alignment_power = 0; + bfdsec->size = payload_len; } + bfdsec->vma = vma; + bfdsec->lma = vma; + bfdsec->alignment_power = 0; + bfdsec->filepos = bfd_tell (abfd); if (bfdsec->size != 0) { - bfdsec->contents = bfd_zalloc (abfd, bfdsec->size); - if (! bfdsec->contents) - goto error_return; - - if (bfd_bread (bfdsec->contents, bfdsec->size, abfd) != bfdsec->size) + bfdsec->contents = _bfd_alloc_and_read (abfd, bfdsec->size, + bfdsec->size); + if (!bfdsec->contents) goto error_return; } @@ -468,16 +476,10 @@ wasm_scan (bfd *abfd) if (error) goto error_return; - return TRUE; + return true; error_return: - if (name) - free (name); - - for (bfdsec = abfd->sections; bfdsec; bfdsec = bfdsec->next) - free ((void *) bfdsec->name); - - return FALSE; + return false; } /* Put a numbered section ASECT of ABFD into the table of numbered @@ -500,7 +502,7 @@ wasm_register_section (bfd *abfd ATTRIBUTE_UNUSED, struct compute_section_arg { bfd_vma pos; - bfd_boolean failed; + bool failed; }; /* Compute the file position of ABFD's section ASECT. FSARG is a @@ -528,7 +530,7 @@ wasm_compute_custom_section_file_position (bfd *abfd, if (idx != 0) return; - if (CONST_STRNEQ (asect->name, WASM_SECTION_PREFIX)) + if (startswith (asect->name, WASM_SECTION_PREFIX)) { const char *name = asect->name + strlen (WASM_SECTION_PREFIX); bfd_size_type payload_len = asect->size; @@ -562,7 +564,7 @@ wasm_compute_custom_section_file_position (bfd *abfd, return; error_return: - fs->failed = TRUE; + fs->failed = true; } /* Compute the file positions for the sections of ABFD. Currently, @@ -573,7 +575,7 @@ wasm_compute_custom_section_file_position (bfd *abfd, their ids, but custom sections can appear in any position and any order, and more than once. FIXME: support that. */ -static bfd_boolean +static bool wasm_compute_section_file_positions (bfd *abfd) { bfd_byte magic[SIZEOF_WASM_MAGIC] = WASM_MAGIC; @@ -586,7 +588,7 @@ wasm_compute_section_file_positions (bfd *abfd) if (bfd_bwrite (magic, sizeof (magic), abfd) != (sizeof magic) || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers)) - return FALSE; + return false; for (i = 0; i < WASM_NUMBERED_SECTIONS; i++) numbered_sections[i] = NULL; @@ -603,27 +605,27 @@ wasm_compute_section_file_positions (bfd *abfd) continue; size = sec->size; if (bfd_seek (abfd, fs.pos, SEEK_SET) != 0) - return FALSE; + return false; if (! wasm_write_uleb128 (abfd, i) || ! wasm_write_uleb128 (abfd, size)) - return FALSE; + return false; fs.pos = sec->filepos = bfd_tell (abfd); fs.pos += size; } - fs.failed = FALSE; + fs.failed = false; bfd_map_over_sections (abfd, wasm_compute_custom_section_file_position, &fs); if (fs.failed) - return FALSE; + return false; - abfd->output_has_begun = TRUE; + abfd->output_has_begun = true; - return TRUE; + return true; } -static bfd_boolean +static bool wasm_set_section_contents (bfd *abfd, sec_ptr section, const void *location, @@ -631,49 +633,49 @@ wasm_set_section_contents (bfd *abfd, bfd_size_type count) { if (count == 0) - return TRUE; + return true; if (! abfd->output_has_begun && ! wasm_compute_section_file_positions (abfd)) - return FALSE; + return false; if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 || bfd_bwrite (location, count, abfd) != count) - return FALSE; + return false; - return TRUE; + return true; } -static bfd_boolean +static bool wasm_write_object_contents (bfd* abfd) { bfd_byte magic[] = WASM_MAGIC; bfd_byte vers[] = WASM_VERSION; if (bfd_seek (abfd, 0, SEEK_SET) != 0) - return FALSE; + return false; if (bfd_bwrite (magic, sizeof (magic), abfd) != sizeof (magic) || bfd_bwrite (vers, sizeof (vers), abfd) != sizeof (vers)) - return FALSE; + return false; - return TRUE; + return true; } -static bfd_boolean +static bool wasm_mkobject (bfd *abfd) { tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); if (! tdata) - return FALSE; + return false; tdata->symbols = NULL; tdata->symcount = 0; abfd->tdata.any = tdata; - return TRUE; + return true; } static long @@ -700,7 +702,7 @@ wasm_canonicalize_symtab (bfd *abfd, asymbol **alocation) static asymbol * wasm_make_empty_symbol (bfd *abfd) { - bfd_size_type amt = sizeof (asymbol); + size_t amt = sizeof (asymbol); asymbol *new_symbol = (asymbol *) bfd_zalloc (abfd, amt); if (! new_symbol) @@ -739,30 +741,37 @@ wasm_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, /* Check whether ABFD is a WebAssembly module; if so, scan it. */ -static const bfd_target * +static bfd_cleanup wasm_object_p (bfd *abfd) { - bfd_boolean error; + bool error; + asection *s; if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return NULL; - if (! wasm_read_header (abfd, &error)) + if (!wasm_read_header (abfd, &error)) { bfd_set_error (bfd_error_wrong_format); return NULL; } - if (! wasm_mkobject (abfd) || ! wasm_scan (abfd)) + if (!wasm_mkobject (abfd)) return NULL; - if (! bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0)) - return NULL; + if (!wasm_scan (abfd) + || !bfd_default_set_arch_mach (abfd, bfd_arch_wasm32, 0)) + { + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = NULL; + return NULL; + } - if (wasm_scan_name_function_section (abfd, bfd_get_section_by_name (abfd, WASM_NAME_SECTION))) + s = bfd_get_section_by_name (abfd, WASM_NAME_SECTION); + if (s != NULL && wasm_scan_name_function_section (abfd, s)) abfd->flags |= HAS_SYMS; - return abfd->xvec; + return _bfd_no_cleanup; } /* BFD_JUMP_TABLE_WRITE */ @@ -792,6 +801,7 @@ const bfd_target wasm_vec = ' ', /* AR_pad_char. */ 255, /* AR_max_namelen. */ 0, /* Match priority. */ + TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols. */ /* Routines to byte-swap various sized integers from the data sections. */ bfd_getl64, bfd_getl_signed_64, bfd_putl64, bfd_getl32, bfd_getl_signed_32, bfd_putl32,