Home | History | Annotate | Download | only in libebl
      1 /* Print contents of object file note.
      2    Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016, 2018 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 #include "common.h"
     41 #include "libelfP.h"
     42 #include "libdwP.h"
     43 #include "memory-access.h"
     44 
     45 
     46 void
     47 ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name, uint32_t type,
     48 		 uint32_t descsz, const char *desc)
     49 {
     50   if (! ebl->object_note (name, type, descsz, desc))
     51     {
     52       /* The machine specific function did not know this type.  */
     53 
     54       if (strcmp ("stapsdt", name) == 0)
     55 	{
     56 	  if (type != 3)
     57 	    {
     58 	      printf (gettext ("unknown SDT version %u\n"), type);
     59 	      return;
     60 	    }
     61 
     62 	  /* Descriptor starts with three addresses, pc, base ref and
     63 	     semaphore.  Then three zero terminated strings provider,
     64 	     name and arguments.  */
     65 
     66 	  union
     67 	  {
     68 	    Elf64_Addr a64[3];
     69 	    Elf32_Addr a32[3];
     70 	  } addrs;
     71 
     72 	  size_t addrs_size = gelf_fsize (ebl->elf, ELF_T_ADDR, 3, EV_CURRENT);
     73 	  if (descsz < addrs_size + 3)
     74 	    {
     75 	    invalid_sdt:
     76 	      printf (gettext ("invalid SDT probe descriptor\n"));
     77 	      return;
     78 	    }
     79 
     80 	  Elf_Data src =
     81 	    {
     82 	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
     83 	      .d_buf = (void *) desc, .d_size = addrs_size
     84 	    };
     85 
     86 	  Elf_Data dst =
     87 	    {
     88 	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
     89 	      .d_buf = &addrs, .d_size = addrs_size
     90 	    };
     91 
     92 	  if (gelf_xlatetom (ebl->elf, &dst, &src,
     93 			     elf_getident (ebl->elf, NULL)[EI_DATA]) == NULL)
     94 	    {
     95 	      printf ("%s\n", elf_errmsg (-1));
     96 	      return;
     97 	    }
     98 
     99 	  const char *provider = desc + addrs_size;
    100 	  const char *pname = memchr (provider, '\0', desc + descsz - provider);
    101 	  if (pname == NULL)
    102 	    goto invalid_sdt;
    103 
    104 	  ++pname;
    105 	  const char *args = memchr (pname, '\0', desc + descsz - pname);
    106 	  if (args == NULL ||
    107 	      memchr (++args, '\0', desc + descsz - pname) != desc + descsz - 1)
    108 	    goto invalid_sdt;
    109 
    110 	  GElf_Addr pc;
    111 	  GElf_Addr base;
    112 	  GElf_Addr sem;
    113 	  if (gelf_getclass (ebl->elf) == ELFCLASS32)
    114 	    {
    115 	      pc = addrs.a32[0];
    116 	      base = addrs.a32[1];
    117 	      sem = addrs.a32[2];
    118 	    }
    119 	  else
    120 	    {
    121 	      pc = addrs.a64[0];
    122 	      base = addrs.a64[1];
    123 	      sem = addrs.a64[2];
    124 	    }
    125 
    126 	  printf (gettext ("    PC: "));
    127 	  printf ("%#" PRIx64 ",", pc);
    128 	  printf (gettext (" Base: "));
    129 	  printf ("%#" PRIx64 ",", base);
    130 	  printf (gettext (" Semaphore: "));
    131 	  printf ("%#" PRIx64 "\n", sem);
    132 	  printf (gettext ("    Provider: "));
    133 	  printf ("%s,", provider);
    134 	  printf (gettext (" Name: "));
    135 	  printf ("%s,", pname);
    136 	  printf (gettext (" Args: "));
    137 	  printf ("'%s'\n", args);
    138 	  return;
    139 	}
    140 
    141       if (strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
    142 		   strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0
    143 	  && (type == NT_GNU_BUILD_ATTRIBUTE_OPEN
    144 	      || type == NT_GNU_BUILD_ATTRIBUTE_FUNC))
    145 	{
    146 	  /* There might or might not be a pair of addresses in the desc.  */
    147 	  if (descsz > 0)
    148 	    {
    149 	      printf ("    Address Range: ");
    150 
    151 	      union
    152 	      {
    153 		Elf64_Addr a64[2];
    154 		Elf32_Addr a32[2];
    155 	      } addrs;
    156 
    157 	      size_t addr_size = gelf_fsize (ebl->elf, ELF_T_ADDR,
    158 					     2, EV_CURRENT);
    159 	      if (descsz != addr_size)
    160 		printf ("<unknown data>\n");
    161 	      else
    162 		{
    163 		  Elf_Data src =
    164 		    {
    165 		     .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
    166 		     .d_buf = (void *) desc, .d_size = descsz
    167 		    };
    168 
    169 		  Elf_Data dst =
    170 		    {
    171 		     .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
    172 		     .d_buf = &addrs, .d_size = descsz
    173 		    };
    174 
    175 		  if (gelf_xlatetom (ebl->elf, &dst, &src,
    176 				     elf_getident (ebl->elf,
    177 						   NULL)[EI_DATA]) == NULL)
    178 		    printf ("%s\n", elf_errmsg (-1));
    179 		  else
    180 		    {
    181 		      if (addr_size == 4)
    182 			printf ("%#" PRIx32 " - %#" PRIx32 "\n",
    183 				addrs.a32[0], addrs.a32[1]);
    184 		      else
    185 			printf ("%#" PRIx64 " - %#" PRIx64 "\n",
    186 				addrs.a64[0], addrs.a64[1]);
    187 		    }
    188 		}
    189 	    }
    190 
    191 	  /* Most data actually is inside the name.
    192 	     https://fedoraproject.org/wiki/Toolchain/Watermark  */
    193 
    194 	  /* We need at least 2 chars of data to describe the
    195 	     attribute and value encodings.  */
    196 	  const char *data = (name
    197 			      + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX));
    198 	  if (namesz < 2)
    199 	    {
    200 	      printf ("<insufficient data>\n");
    201 	      return;
    202 	    }
    203 
    204 	  printf ("    ");
    205 
    206 	  /* In most cases the value comes right after the encoding bytes.  */
    207 	  const char *value = &data[2];
    208 	  switch (data[1])
    209 	    {
    210 	    case GNU_BUILD_ATTRIBUTE_VERSION:
    211 	      printf ("VERSION: ");
    212 	      break;
    213 	    case GNU_BUILD_ATTRIBUTE_STACK_PROT:
    214 	      printf ("STACK_PROT: ");
    215 	      break;
    216 	    case GNU_BUILD_ATTRIBUTE_RELRO:
    217 	      printf ("RELRO: ");
    218 	      break;
    219 	    case GNU_BUILD_ATTRIBUTE_STACK_SIZE:
    220 	      printf ("STACK_SIZE: ");
    221 	      break;
    222 	    case GNU_BUILD_ATTRIBUTE_TOOL:
    223 	      printf ("TOOL: ");
    224 	      break;
    225 	    case GNU_BUILD_ATTRIBUTE_ABI:
    226 	      printf ("ABI: ");
    227 	      break;
    228 	    case GNU_BUILD_ATTRIBUTE_PIC:
    229 	      printf ("PIC: ");
    230 	      break;
    231 	    case GNU_BUILD_ATTRIBUTE_SHORT_ENUM:
    232 	      printf ("SHORT_ENUM: ");
    233 	      break;
    234 	    case 32 ... 126:
    235 	      printf ("\"%s\": ", &data[1]);
    236 	      value += strlen (&data[1]) + 1;
    237 	      break;
    238 	    default:
    239 	      printf ("<unknown>: ");
    240 	      break;
    241 	    }
    242 
    243 	  switch (data[0])
    244 	    {
    245 	    case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
    246 	      {
    247 		/* Any numbers are always in (unsigned) little endian.  */
    248 		static const Dwarf dbg
    249 		  = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB };
    250 		size_t bytes = namesz - (value - name);
    251 		uint64_t val;
    252 		if (bytes == 1)
    253 		  val = *(unsigned char *) value;
    254 		else if (bytes == 2)
    255 		  val = read_2ubyte_unaligned (&dbg, value);
    256 		else if (bytes == 4)
    257 		  val = read_4ubyte_unaligned (&dbg, value);
    258 		else if (bytes == 8)
    259 		  val = read_8ubyte_unaligned (&dbg, value);
    260 		else
    261 		  goto unknown;
    262 		printf ("%" PRIx64, val);
    263 	      }
    264 	      break;
    265 	    case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
    266 	      printf ("\"%s\"", value);
    267 	      break;
    268 	    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
    269 	      printf ("TRUE");
    270 	      break;
    271 	    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
    272 	      printf ("FALSE");
    273 	      break;
    274 	    default:
    275 	      {
    276 	      unknown:
    277 		printf ("<unknown>");
    278 	      }
    279 	      break;
    280 	    }
    281 
    282 	  printf ("\n");
    283 
    284 	  return;
    285 	}
    286 
    287       /* NT_VERSION doesn't have any info.  All data is in the name.  */
    288       if (descsz == 0 && type == NT_VERSION)
    289 	return;
    290 
    291       /* Everything else should have the "GNU" owner name.  */
    292       if (strcmp ("GNU", name) != 0)
    293 	return;
    294 
    295       switch (type)
    296 	{
    297 	case NT_GNU_BUILD_ID:
    298 	  if (strcmp (name, "GNU") == 0 && descsz > 0)
    299 	    {
    300 	      printf (gettext ("    Build ID: "));
    301 	      uint_fast32_t i;
    302 	      for (i = 0; i < descsz - 1; ++i)
    303 		printf ("%02" PRIx8, (uint8_t) desc[i]);
    304 	      printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
    305 	    }
    306 	  break;
    307 
    308 	case NT_GNU_GOLD_VERSION:
    309 	  if (strcmp (name, "GNU") == 0 && descsz > 0)
    310 	    /* A non-null terminated version string.  */
    311 	    printf (gettext ("    Linker version: %.*s\n"),
    312 		    (int) descsz, desc);
    313 	  break;
    314 
    315 	case NT_GNU_PROPERTY_TYPE_0:
    316 	  if (strcmp (name, "GNU") == 0 && descsz > 0)
    317 	    {
    318 	      /* There are at least 2 words. type and datasz.  */
    319 	      while (descsz >= 8)
    320 		{
    321 		  struct pr_prop
    322 		  {
    323 		    GElf_Word pr_type;
    324 		    GElf_Word pr_datasz;
    325 		  } prop;
    326 
    327 		  Elf_Data in =
    328 		    {
    329 		      .d_version = EV_CURRENT,
    330 		      .d_type = ELF_T_WORD,
    331 		      .d_size = 8,
    332 		      .d_buf = (void *) desc
    333 		    };
    334 		  Elf_Data out =
    335 		    {
    336 		      .d_version = EV_CURRENT,
    337 		      .d_type = ELF_T_WORD,
    338 		      .d_size = descsz,
    339 		      .d_buf = (void *) &prop
    340 		    };
    341 
    342 		  if (gelf_xlatetom (ebl->elf, &out, &in,
    343 				     elf_getident (ebl->elf,
    344 						   NULL)[EI_DATA]) == NULL)
    345 		    {
    346 		      printf ("%s\n", elf_errmsg (-1));
    347 		      return;
    348 		    }
    349 
    350 		  desc += 8;
    351 		  descsz -= 8;
    352 
    353 		  if (prop.pr_datasz > descsz)
    354 		    {
    355 		      printf ("BAD property datasz: %" PRId32 "\n",
    356 			      prop.pr_datasz);
    357 		      return;
    358 		    }
    359 
    360 		  int elfclass = gelf_getclass (ebl->elf);
    361 		  char *elfident = elf_getident (ebl->elf, NULL);
    362 		  GElf_Ehdr ehdr;
    363 		  gelf_getehdr (ebl->elf, &ehdr);
    364 
    365 		  /* Prefix.  */
    366 		  printf ("    ");
    367 		  if (prop.pr_type == GNU_PROPERTY_STACK_SIZE)
    368 		    {
    369 		      printf ("STACK_SIZE ");
    370 		      union
    371 			{
    372 			  Elf64_Addr a64;
    373 			  Elf32_Addr a32;
    374 			} addr;
    375 		      if ((elfclass == ELFCLASS32 && prop.pr_datasz == 4)
    376 			  || (elfclass == ELFCLASS64 && prop.pr_datasz == 8))
    377 			{
    378 			  in.d_type = ELF_T_ADDR;
    379 			  out.d_type = ELF_T_ADDR;
    380 			  in.d_size = prop.pr_datasz;
    381 			  out.d_size = prop.pr_datasz;
    382 			  in.d_buf = (void *) desc;
    383 			  out.d_buf = (elfclass == ELFCLASS32
    384 				       ? (void *) &addr.a32
    385 				       : (void *) &addr.a64);
    386 
    387 			  if (gelf_xlatetom (ebl->elf, &out, &in,
    388 					     elfident[EI_DATA]) == NULL)
    389 			    {
    390 			      printf ("%s\n", elf_errmsg (-1));
    391 			      return;
    392 			    }
    393 			  if (elfclass == ELFCLASS32)
    394 			    printf ("%#" PRIx32 "\n", addr.a32);
    395 			  else
    396 			    printf ("%#" PRIx64 "\n", addr.a64);
    397 			}
    398 		      else
    399 			printf (" (garbage datasz: %" PRIx32 ")\n",
    400 				prop.pr_datasz);
    401 		    }
    402 		  else if (prop.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
    403 		    {
    404 		      printf ("NO_COPY_ON_PROTECTION");
    405 		      if (prop.pr_datasz == 0)
    406 			printf ("\n");
    407 		      else
    408 			printf (" (garbage datasz: %" PRIx32 ")\n",
    409 				prop.pr_datasz);
    410 		    }
    411 		  else if (prop.pr_type >= GNU_PROPERTY_LOPROC
    412 		      && prop.pr_type <= GNU_PROPERTY_HIPROC
    413 		      && (ehdr.e_machine == EM_386
    414 			  || ehdr.e_machine == EM_X86_64))
    415 		    {
    416 		      printf ("X86 ");
    417 		      if (prop.pr_type == GNU_PROPERTY_X86_FEATURE_1_AND)
    418 			{
    419 			  printf ("FEATURE_1_AND: ");
    420 
    421 			  if (prop.pr_datasz == 4)
    422 			    {
    423 			      GElf_Word data;
    424 			      in.d_type = ELF_T_WORD;
    425 			      out.d_type = ELF_T_WORD;
    426 			      in.d_size = 4;
    427 			      out.d_size = 4;
    428 			      in.d_buf = (void *) desc;
    429 			      out.d_buf = (void *) &data;
    430 
    431 			      if (gelf_xlatetom (ebl->elf, &out, &in,
    432 						 elfident[EI_DATA]) == NULL)
    433 				{
    434 				  printf ("%s\n", elf_errmsg (-1));
    435 				  return;
    436 				}
    437 			      printf ("%08" PRIx32 " ", data);
    438 
    439 			      if ((data & GNU_PROPERTY_X86_FEATURE_1_IBT)
    440 				  != 0)
    441 				{
    442 				  printf ("IBT");
    443 				  data &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
    444 				  if (data != 0)
    445 				    printf (" ");
    446 				}
    447 
    448 			      if ((data & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
    449 				  != 0)
    450 				{
    451 				  printf ("SHSTK");
    452 				  data &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
    453 				  if (data != 0)
    454 				    printf (" ");
    455 				}
    456 
    457 			      if (data != 0)
    458 				printf ("UNKNOWN");
    459 			    }
    460 			  else
    461 			    printf ("<bad datasz: %" PRId32 ">",
    462 				    prop.pr_datasz);
    463 
    464 			  printf ("\n");
    465 			}
    466 		      else
    467 			{
    468 			  printf ("%#" PRIx32, prop.pr_type);
    469 			  if (prop.pr_datasz > 0)
    470 			    {
    471 			      printf (" data: ");
    472 			      size_t i;
    473 			      for (i = 0; i < prop.pr_datasz - 1; i++)
    474 				printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
    475 			      printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
    476 			    }
    477 			}
    478 		    }
    479 		  else
    480 		    {
    481 		      if (prop.pr_type >= GNU_PROPERTY_LOPROC
    482 			  && prop.pr_type <= GNU_PROPERTY_HIPROC)
    483 			printf ("proc_type %#" PRIx32, prop.pr_type);
    484 		      else if (prop.pr_type >= GNU_PROPERTY_LOUSER
    485 			  && prop.pr_type <= GNU_PROPERTY_HIUSER)
    486 			printf ("app_type %#" PRIx32, prop.pr_type);
    487 		      else
    488 			printf ("unknown_type %#" PRIx32, prop.pr_type);
    489 
    490 		      if (prop.pr_datasz > 0)
    491 			{
    492 			  printf (" data: ");
    493 			  size_t i;
    494 			  for (i = 0; i < prop.pr_datasz - 1; i++)
    495 			    printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
    496 			  printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
    497 			}
    498 		    }
    499 
    500 		  if (elfclass == ELFCLASS32)
    501 		    prop.pr_datasz = NOTE_ALIGN4 (prop.pr_datasz);
    502 		  else
    503 		    prop.pr_datasz = NOTE_ALIGN8 (prop.pr_datasz);
    504 
    505 		  desc += prop.pr_datasz;
    506 		  if (descsz > prop.pr_datasz)
    507 		    descsz -= prop.pr_datasz;
    508 		  else
    509 		    descsz = 0;
    510 		}
    511 	    }
    512 	  break;
    513 
    514 	case NT_GNU_ABI_TAG:
    515 	  if (descsz >= 8 && descsz % 4 == 0)
    516 	    {
    517 	      Elf_Data in =
    518 		{
    519 		  .d_version = EV_CURRENT,
    520 		  .d_type = ELF_T_WORD,
    521 		  .d_size = descsz,
    522 		  .d_buf = (void *) desc
    523 		};
    524 	      /* Normally NT_GNU_ABI_TAG is just 4 words (16 bytes).  If it
    525 		 is much (4*) larger dynamically allocate memory to convert.  */
    526 #define FIXED_TAG_BYTES 16
    527 	      uint32_t sbuf[FIXED_TAG_BYTES];
    528 	      uint32_t *buf;
    529 	      if (unlikely (descsz / 4 > FIXED_TAG_BYTES))
    530 		{
    531 		  buf = malloc (descsz);
    532 		  if (unlikely (buf == NULL))
    533 		    return;
    534 		}
    535 	      else
    536 		buf = sbuf;
    537 	      Elf_Data out =
    538 		{
    539 		  .d_version = EV_CURRENT,
    540 		  .d_type = ELF_T_WORD,
    541 		  .d_size = descsz,
    542 		  .d_buf = buf
    543 		};
    544 
    545 	      if (elf32_xlatetom (&out, &in, ebl->data) != NULL)
    546 		{
    547 		  const char *os;
    548 		  switch (buf[0])
    549 		    {
    550 		    case ELF_NOTE_OS_LINUX:
    551 		      os = "Linux";
    552 		      break;
    553 
    554 		    case ELF_NOTE_OS_GNU:
    555 		      os = "GNU";
    556 		      break;
    557 
    558 		    case ELF_NOTE_OS_SOLARIS2:
    559 		      os = "Solaris";
    560 		      break;
    561 
    562 		    case ELF_NOTE_OS_FREEBSD:
    563 		      os = "FreeBSD";
    564 		      break;
    565 
    566 		    default:
    567 		      os = "???";
    568 		      break;
    569 		    }
    570 
    571 		  printf (gettext ("    OS: %s, ABI: "), os);
    572 		  for (size_t cnt = 1; cnt < descsz / 4; ++cnt)
    573 		    {
    574 		      if (cnt > 1)
    575 			putchar_unlocked ('.');
    576 		      printf ("%" PRIu32, buf[cnt]);
    577 		    }
    578 		  putchar_unlocked ('\n');
    579 		}
    580 	      if (descsz / 4 > FIXED_TAG_BYTES)
    581 		free (buf);
    582 	      break;
    583 	    }
    584 	  FALLTHROUGH;
    585 
    586 	default:
    587 	  /* Unknown type.  */
    588 	  break;
    589 	}
    590     }
    591 }
    592