| /* 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" |
| #include "ldbuildid.h" |
| #ifdef __MINGW32__ |
| #include <windows.h> |
| #include <rpcdce.h> |
| #endif |
| |
| #define streq(a,b) strcmp ((a), (b)) == 0 |
| |
| bool |
| validate_build_id_style (const char *style) |
| { |
| if ((streq (style, "md5")) || (streq (style, "sha1")) |
| || (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; |
| |
| 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; |
| } |
| |
| bool |
| generate_build_id (bfd *abfd, |
| const char *style, |
| checksum_fn checksum_contents, |
| unsigned char *id_bits, |
| int size ATTRIBUTE_UNUSED) |
| { |
| 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; |
| } |