(root)/
binutils-2.41/
ld/
ldbuildid.c
       1  /* ldbuildid.c - Build Id support routines
       2     Copyright (C) 2013-2023 Free Software Foundation, Inc.
       3  
       4     This file is part of the GNU Binutils.
       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  #include "sysdep.h"
      22  #include "bfd.h"
      23  #include "safe-ctype.h"
      24  #include "md5.h"
      25  #include "sha1.h"
      26  #include "ldbuildid.h"
      27  #ifdef __MINGW32__
      28  #include <windows.h>
      29  #include <rpcdce.h>
      30  #endif
      31  
      32  #define streq(a,b)     strcmp ((a), (b)) == 0
      33  
      34  bool
      35  validate_build_id_style (const char *style)
      36  {
      37    if ((streq (style, "md5")) || (streq (style, "sha1"))
      38        || (streq (style, "uuid")) || (startswith (style, "0x")))
      39      return true;
      40  
      41    return false;
      42  }
      43  
      44  bfd_size_type
      45  compute_build_id_size (const char *style)
      46  {
      47    if (streq (style, "md5") || streq (style, "uuid"))
      48      return 128 / 8;
      49  
      50    if (streq (style, "sha1"))
      51      return 160 / 8;
      52  
      53    if (startswith (style, "0x"))
      54      {
      55        bfd_size_type size = 0;
      56        /* ID is in string form (hex).  Count the bytes.  */
      57        const char *id = style + 2;
      58  
      59        do
      60  	{
      61  	  if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
      62  	    {
      63  	      ++size;
      64  	      id += 2;
      65  	    }
      66  	  else if (*id == '-' || *id == ':')
      67  	    ++id;
      68  	  else
      69  	    {
      70  	      size = 0;
      71  	      break;
      72  	    }
      73  	} while (*id != '\0');
      74        return size;
      75      }
      76  
      77    return 0;
      78  }
      79  
      80  static unsigned char
      81  read_hex (const char xdigit)
      82  {
      83    if (ISDIGIT (xdigit))
      84      return xdigit - '0';
      85  
      86    if (ISUPPER (xdigit))
      87      return xdigit - 'A' + 0xa;
      88  
      89    if (ISLOWER (xdigit))
      90      return xdigit - 'a' + 0xa;
      91  
      92    abort ();
      93    return 0;
      94  }
      95  
      96  bool
      97  generate_build_id (bfd *abfd,
      98  		   const char *style,
      99  		   checksum_fn checksum_contents,
     100  		   unsigned char *id_bits,
     101  		   int size ATTRIBUTE_UNUSED)
     102  {
     103    if (streq (style, "md5"))
     104      {
     105        struct md5_ctx ctx;
     106  
     107        md5_init_ctx (&ctx);
     108        if (!(*checksum_contents) (abfd, (sum_fn) &md5_process_bytes, &ctx))
     109  	return false;
     110        md5_finish_ctx (&ctx, id_bits);
     111      }
     112    else if (streq (style, "sha1"))
     113      {
     114        struct sha1_ctx ctx;
     115  
     116        sha1_init_ctx (&ctx);
     117        if (!(*checksum_contents) (abfd, (sum_fn) &sha1_process_bytes, &ctx))
     118  	return false;
     119        sha1_finish_ctx (&ctx, id_bits);
     120      }
     121    else if (streq (style, "uuid"))
     122      {
     123  #ifndef __MINGW32__
     124        int n;
     125        int fd = open ("/dev/urandom", O_RDONLY);
     126  
     127        if (fd < 0)
     128  	return false;
     129        n = read (fd, id_bits, size);
     130        close (fd);
     131        if (n < size)
     132  	return false;
     133  #else /* __MINGW32__ */
     134        typedef RPC_STATUS (RPC_ENTRY * UuidCreateFn) (UUID *);
     135        UUID          uuid;
     136        UuidCreateFn  uuid_create = 0;
     137        HMODULE       rpc_library = LoadLibrary ("rpcrt4.dll");
     138  
     139        if (!rpc_library)
     140  	return false;
     141        uuid_create = (UuidCreateFn) (void (WINAPI *)(void)) GetProcAddress (rpc_library, "UuidCreate");
     142        if (!uuid_create)
     143  	{
     144  	  FreeLibrary (rpc_library);
     145  	  return false;
     146  	}
     147  
     148        if (uuid_create (&uuid) != RPC_S_OK)
     149  	{
     150  	  FreeLibrary (rpc_library);
     151  	  return false;
     152  	}
     153        FreeLibrary (rpc_library);
     154        memcpy (id_bits, &uuid,
     155  	      (size_t) size < sizeof (UUID) ? (size_t) size : sizeof (UUID));
     156  #endif /* __MINGW32__ */
     157      }
     158    else if (startswith (style, "0x"))
     159      {
     160        /* ID is in string form (hex).  Convert to bits.  */
     161        const char *id = style + 2;
     162        size_t n = 0;
     163  
     164        do
     165  	{
     166  	  if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
     167  	    {
     168  	      id_bits[n] = read_hex (*id++) << 4;
     169  	      id_bits[n++] |= read_hex (*id++);
     170  	    }
     171  	  else if (*id == '-' || *id == ':')
     172  	    ++id;
     173  	  else
     174  	    abort ();		/* Should have been validated earlier.  */
     175  	}
     176        while (*id != '\0');
     177      }
     178    else
     179      abort ();			/* Should have been validated earlier.  */
     180  
     181    return true;
     182  }