Home | History | Annotate | Download | only in libebl
      1 /* Print contents of object file note.
      2    Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016 Red Hat, Inc.
      3    This file is part of elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2002.
      5 
      6    This file is free software; you can redistribute it and/or modify
      7    it under the terms of either
      8 
      9      * the GNU Lesser General Public License as published by the Free
     10        Software Foundation; either version 3 of the License, or (at
     11        your option) any later version
     12 
     13    or
     14 
     15      * the GNU General Public License as published by the Free
     16        Software Foundation; either version 2 of the License, or (at
     17        your option) any later version
     18 
     19    or both in parallel, as here.
     20 
     21    elfutils is distributed in the hope that it will be useful, but
     22    WITHOUT ANY WARRANTY; without even the implied warranty of
     23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     24    General Public License for more details.
     25 
     26    You should have received copies of the GNU General Public License and
     27    the GNU Lesser General Public License along with this program.  If
     28    not, see <http://www.gnu.org/licenses/>.  */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 # include <config.h>
     32 #endif
     33 
     34 #include <inttypes.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <string.h>
     38 #include <libeblP.h>
     39 
     40 
     41 void
     42 ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
     43 		 uint32_t descsz, const char *desc)
     44 {
     45   if (! ebl->object_note (name, type, descsz, desc))
     46     {
     47       /* The machine specific function did not know this type.  */
     48 
     49       if (strcmp ("stapsdt", name) == 0)
     50 	{
     51 	  if (type != 3)
     52 	    {
     53 	      printf (gettext ("unknown SDT version %u\n"), type);
     54 	      return;
     55 	    }
     56 
     57 	  /* Descriptor starts with three addresses, pc, base ref and
     58 	     semaphore.  Then three zero terminated strings provider,
     59 	     name and arguments.  */
     60 
     61 	  union
     62 	  {
     63 	    Elf64_Addr a64[3];
     64 	    Elf32_Addr a32[3];
     65 	  } addrs;
     66 
     67 	  size_t addrs_size = gelf_fsize (ebl->elf, ELF_T_ADDR, 3, EV_CURRENT);
     68 	  if (descsz < addrs_size + 3)
     69 	    {
     70 	    invalid_sdt:
     71 	      printf (gettext ("invalid SDT probe descriptor\n"));
     72 	      return;
     73 	    }
     74 
     75 	  Elf_Data src =
     76 	    {
     77 	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
     78 	      .d_buf = (void *) desc, .d_size = addrs_size
     79 	    };
     80 
     81 	  Elf_Data dst =
     82 	    {
     83 	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
     84 	      .d_buf = &addrs, .d_size = addrs_size
     85 	    };
     86 
     87 	  if (gelf_xlatetom (ebl->elf, &dst, &src,
     88 			     elf_getident (ebl->elf, NULL)[EI_DATA]) == NULL)
     89 	    {
     90 	      printf ("%s\n", elf_errmsg (-1));
     91 	      return;
     92 	    }
     93 
     94 	  const char *provider = desc + addrs_size;
     95 	  const char *pname = memchr (provider, '\0', desc + descsz - provider);
     96 	  if (pname == NULL)
     97 	    goto invalid_sdt;
     98 
     99 	  ++pname;
    100 	  const char *args = memchr (pname, '\0', desc + descsz - pname);
    101 	  if (args == NULL ||
    102 	      memchr (++args, '\0', desc + descsz - pname) != desc + descsz - 1)
    103 	    goto invalid_sdt;
    104 
    105 	  GElf_Addr pc;
    106 	  GElf_Addr base;
    107 	  GElf_Addr sem;
    108 	  if (gelf_getclass (ebl->elf) == ELFCLASS32)
    109 	    {
    110 	      pc = addrs.a32[0];
    111 	      base = addrs.a32[1];
    112 	      sem = addrs.a32[2];
    113 	    }
    114 	  else
    115 	    {
    116 	      pc = addrs.a64[0];
    117 	      base = addrs.a64[1];
    118 	      sem = addrs.a64[2];
    119 	    }
    120 
    121 	  printf (gettext ("    PC: "));
    122 	  printf ("%#" PRIx64 ",", pc);
    123 	  printf (gettext (" Base: "));
    124 	  printf ("%#" PRIx64 ",", base);
    125 	  printf (gettext (" Semaphore: "));
    126 	  printf ("%#" PRIx64 "\n", sem);
    127 	  printf (gettext ("    Provider: "));
    128 	  printf ("%s,", provider);
    129 	  printf (gettext (" Name: "));
    130 	  printf ("%s,", pname);
    131 	  printf (gettext (" Args: "));
    132 	  printf ("'%s'\n", args);
    133 	  return;
    134 	}
    135 
    136       switch (type)
    137 	{
    138 	case NT_GNU_BUILD_ID:
    139 	  if (strcmp (name, "GNU") == 0 && descsz > 0)
    140 	    {
    141 	      printf (gettext ("    Build ID: "));
    142 	      uint_fast32_t i;
    143 	      for (i = 0; i < descsz - 1; ++i)
    144 		printf ("%02" PRIx8, (uint8_t) desc[i]);
    145 	      printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
    146 	    }
    147 	  break;
    148 
    149 	case NT_GNU_GOLD_VERSION:
    150 	  if (strcmp (name, "GNU") == 0 && descsz > 0)
    151 	    /* A non-null terminated version string.  */
    152 	    printf (gettext ("    Linker version: %.*s\n"),
    153 		    (int) descsz, desc);
    154 	  break;
    155 
    156 	case NT_GNU_ABI_TAG:
    157 	  if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
    158 	    {
    159 	      Elf_Data in =
    160 		{
    161 		  .d_version = EV_CURRENT,
    162 		  .d_type = ELF_T_WORD,
    163 		  .d_size = descsz,
    164 		  .d_buf = (void *) desc
    165 		};
    166 	      /* Normally NT_GNU_ABI_TAG is just 4 words (16 bytes).  If it
    167 		 is much (4*) larger dynamically allocate memory to convert.  */
    168 #define FIXED_TAG_BYTES 16
    169 	      uint32_t sbuf[FIXED_TAG_BYTES];
    170 	      uint32_t *buf;
    171 	      if (unlikely (descsz / 4 > FIXED_TAG_BYTES))
    172 		{
    173 		  buf = malloc (descsz);
    174 		  if (unlikely (buf == NULL))
    175 		    return;
    176 		}
    177 	      else
    178 		buf = sbuf;
    179 	      Elf_Data out =
    180 		{
    181 		  .d_version = EV_CURRENT,
    182 		  .d_type = ELF_T_WORD,
    183 		  .d_size = descsz,
    184 		  .d_buf = buf
    185 		};
    186 
    187 	      if (elf32_xlatetom (&out, &in, ebl->data) != NULL)
    188 		{
    189 		  const char *os;
    190 		  switch (buf[0])
    191 		    {
    192 		    case ELF_NOTE_OS_LINUX:
    193 		      os = "Linux";
    194 		      break;
    195 
    196 		    case ELF_NOTE_OS_GNU:
    197 		      os = "GNU";
    198 		      break;
    199 
    200 		    case ELF_NOTE_OS_SOLARIS2:
    201 		      os = "Solaris";
    202 		      break;
    203 
    204 		    case ELF_NOTE_OS_FREEBSD:
    205 		      os = "FreeBSD";
    206 		      break;
    207 
    208 		    default:
    209 		      os = "???";
    210 		      break;
    211 		    }
    212 
    213 		  printf (gettext ("    OS: %s, ABI: "), os);
    214 		  for (size_t cnt = 1; cnt < descsz / 4; ++cnt)
    215 		    {
    216 		      if (cnt > 1)
    217 			putchar_unlocked ('.');
    218 		      printf ("%" PRIu32, buf[cnt]);
    219 		    }
    220 		  putchar_unlocked ('\n');
    221 		}
    222 	      if (descsz / 4 > FIXED_TAG_BYTES)
    223 		free (buf);
    224 	      break;
    225 	    }
    226 	  /* FALLTHROUGH */
    227 
    228 	default:
    229 	  /* Unknown type.  */
    230 	  break;
    231 	}
    232     }
    233 }
    234