/* ldbuildid.c - Build Id support routines Copyright (C) 2013-2024 Free Software Foundation, Inc. This file is part of the GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sysdep.h" #include "bfd.h" #include "safe-ctype.h" #include "md5.h" #include "sha1.h" #ifdef WITH_XXHASH #define XXH_INLINE_ALL #include #endif #include "ldbuildid.h" #ifdef __MINGW32__ #include #include #endif #define streq(a,b) strcmp ((a), (b)) == 0 bool validate_build_id_style (const char *style) { if ((streq (style, "md5")) || (streq (style, "sha1")) #ifdef WITH_XXHASH || (streq (style, "xx")) #endif || (streq (style, "uuid")) || (startswith (style, "0x"))) return true; return false; } bfd_size_type compute_build_id_size (const char *style) { if (streq (style, "md5") || streq (style, "uuid")) return 128 / 8; #ifdef WITH_XXHASH if (streq (style, "xx")) return 128 / 8; #endif if (streq (style, "sha1")) return 160 / 8; if (startswith (style, "0x")) { bfd_size_type size = 0; /* ID is in string form (hex). Count the bytes. */ const char *id = style + 2; do { if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) { ++size; id += 2; } else if (*id == '-' || *id == ':') ++id; else { size = 0; break; } } while (*id != '\0'); return size; } return 0; } static unsigned char read_hex (const char xdigit) { if (ISDIGIT (xdigit)) return xdigit - '0'; if (ISUPPER (xdigit)) return xdigit - 'A' + 0xa; if (ISLOWER (xdigit)) return xdigit - 'a' + 0xa; abort (); return 0; } #ifdef WITH_XXHASH static void xx_process_bytes(const void* buffer, size_t size, void* state) { XXH3_128bits_update ((XXH3_state_t*) state, buffer, size); } #endif bool generate_build_id (bfd *abfd, const char *style, checksum_fn checksum_contents, unsigned char *id_bits, int size ATTRIBUTE_UNUSED) { #ifdef WITH_XXHASH if (streq (style, "xx")) { XXH3_state_t* state = XXH3_createState (); if (!state) { return false; } XXH3_128bits_reset (state); if (!(*checksum_contents) (abfd, &xx_process_bytes, state)) { XXH3_freeState (state); return false; } XXH128_hash_t result = XXH3_128bits_digest (state); XXH3_freeState (state); /* Use canonical-endianness output. */ XXH128_canonical_t result_canon; XXH128_canonicalFromHash (&result_canon, result); memcpy (id_bits, &result_canon, (size_t) size < sizeof (result) ? (size_t) size : sizeof (result)); } else #endif if (streq (style, "md5")) { struct md5_ctx ctx; md5_init_ctx (&ctx); if (!(*checksum_contents) (abfd, (sum_fn) &md5_process_bytes, &ctx)) return false; md5_finish_ctx (&ctx, id_bits); } else if (streq (style, "sha1")) { struct sha1_ctx ctx; sha1_init_ctx (&ctx); if (!(*checksum_contents) (abfd, (sum_fn) sha1_choose_process_bytes (), &ctx)) return false; sha1_finish_ctx (&ctx, id_bits); } else if (streq (style, "uuid")) { #ifndef __MINGW32__ int n; int fd = open ("/dev/urandom", O_RDONLY); if (fd < 0) return false; n = read (fd, id_bits, size); close (fd); if (n < size) return false; #else /* __MINGW32__ */ typedef RPC_STATUS (RPC_ENTRY * UuidCreateFn) (UUID *); UUID uuid; UuidCreateFn uuid_create = 0; HMODULE rpc_library = LoadLibrary ("rpcrt4.dll"); if (!rpc_library) return false; uuid_create = (UuidCreateFn) (void (WINAPI *)(void)) GetProcAddress (rpc_library, "UuidCreate"); if (!uuid_create) { FreeLibrary (rpc_library); return false; } if (uuid_create (&uuid) != RPC_S_OK) { FreeLibrary (rpc_library); return false; } FreeLibrary (rpc_library); memcpy (id_bits, &uuid, (size_t) size < sizeof (UUID) ? (size_t) size : sizeof (UUID)); #endif /* __MINGW32__ */ } else if (startswith (style, "0x")) { /* ID is in string form (hex). Convert to bits. */ const char *id = style + 2; size_t n = 0; do { if (ISXDIGIT (id[0]) && ISXDIGIT (id[1])) { id_bits[n] = read_hex (*id++) << 4; id_bits[n++] |= read_hex (*id++); } else if (*id == '-' || *id == ':') ++id; else abort (); /* Should have been validated earlier. */ } while (*id != '\0'); } else abort (); /* Should have been validated earlier. */ return true; }