From a0f4d5897c51fc7299f410b2e27b85db057c49af Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 21 Dec 2017 17:16:44 +0000 Subject: [PATCH] Version 3 of protocol --- doc/annotation.proposal.txt | 73 ++++++---- plugin/aarch64.annobin.cc | 12 +- plugin/annobin.cc | 260 ++++++++++++++++++++++++++---------- plugin/annobin.h | 14 +- plugin/dummy.annobin.cc | 2 +- plugin/powerpc.annobin.cc | 13 +- plugin/x86_64.annobin.cc | 14 +- tests/Makefile.am | 2 +- tests/Makefile.in | 2 +- tests/hello.c | 6 + tests/missing-notes-test | 50 +++++++ 11 files changed, 316 insertions(+), 132 deletions(-) create mode 100755 tests/missing-notes-test diff --git a/doc/annotation.proposal.txt b/doc/annotation.proposal.txt index c067e37..24264f3 100644 --- a/doc/annotation.proposal.txt +++ b/doc/annotation.proposal.txt @@ -1,12 +1,16 @@ Storing Build Time Information In ELF Binary Files In a Format Suitable for Static Analysis - A specification by Nick Clifton. Version 2.0. June 28, 2017. + A specification by Nick Clifton. Version 3.0. Dec 20, 2017. ChangeLog: + For v3.0: + Add end-of-range addresses to description field, to allow + for gaps in the coverage. + For v2.0: Added an "owner" string at the start of the name field so that - naive processors of Elf Notes are less likely to complain. + naive processors of Elf Notes are less likely to complain. ---------------------------------------------------------------------- @@ -58,32 +62,25 @@ ChangeLog: Two new note types are defined: NT_GNU_BUILD_ATTRIBUTE_OPEN (0x100) and NT_GNU_BUILD_ATTRIBUTE_FUNC (0x101). These are used by the description field (see below). - - The description field of the note is a 4-byte or 8-byte wide address - which indicates the starting location for an attribute. If the - bottom bit of the type field is set then the address is for a - function and the attribute terminates at the end of the function. - (Reverting back to the previous value for that attribute). If the - bottom bit of the type is clear then the address is for the start of - an open ended range. The range ends only when another open-ended - attribute of the same name is defined, although it may be - temporarily overridden by a function based address. - - Notes: - - + In unrelocated files the numbers should instead be zero, with a - relocation present to set the actual value once the file is - linked. - + The numbers are stored in the same endian format as that - specified in the EI_DATA field of the ELF header of the file - containing the note. The size of the numbers is dictated by the - EI_CLASS field of the ELF header. - + An empty description field is a special case. It should be - treated as if it applies to the same region as the nearest - preceeding NT_GNU_BUILD_ATTRIBUTE_OPEN note with a non-empty - description field. This will probably be a version note. + The description field of the note is either 0-bytes long, or else a + pair of 4-byte wide (for 32-bit targets) or 8-byte wide (for 64-bit + targets) addresses which indicate the starting and ending location + for the attribute. + + If the description field is empty, the note should be treated as if + it applies to the same region as the nearest preceeding note of the + same type (ie either OPEN or FUNC). + + In unrelocated files the addresses should instead be zero, with a + relocation present to set the actual value once the file is linked. + + The numbers are stored in the same endian format as that specified + in the EI_DATA field of the ELF header of the file containing the + note. The size of the numbers is dictated by the EI_CLASS field of + the ELF header. + The name field identifies the type and value of the attribute. The name starts with the string "GA", which is an abbreviation for @@ -104,8 +101,7 @@ ChangeLog: Character Allowed Meaning --------------- Types ------- - ASCII printable $* An annotation type not explicitly defined by this specification. This string must be NUL terminated. - 0 Reserved for future use. + - Reserved for future use. 1 $ Version of the specification supported and producer(s) of the notes (see below). 2 * Stack protector 3 !+ Relro @@ -114,6 +110,9 @@ ChangeLog: 6 $* ABI 7 * Position Independence Status: 0 => static, 1 => pic, 2 => PIC, 3 => pie 8 !+ Short enums + 9..30 Reserved for future use. + 31..126 $* An annotation type not explicitly defined by this specification. + 127+ Reserved for future use. For * and $ type attributes the value is then appended. @@ -147,6 +146,18 @@ Some examples: identifying pair of characters should be appended to the version note. + The description field for the version note should not be empty. + This note serves as the base address for other open notes that + follow, allowing them to use an empty description field. + + The last note should be an end-note (ascii value 0) which specifies + the end address of the range covered by the previous open notes. If + no end note is present then the address range is presumed to be open + at the higher end. + + End-notes can also be used to indicate the end of a function + specific note's address range. These notes must have the + NT_GNU_BUILD_ATTRIBUTE_FUNC type. * When the linker merges two or more files containing these notes it should ensure that the above rules are maintained. Simply @@ -167,11 +178,14 @@ Some examples: The linker, or another tool, may wish to eliminate redundant notes in the note section. When doing this the following rules must be observed: + 0. [Optional] If relocations exist against the notes then + they should not be merged. 1. Preserve the ordering of the notes. 2. Preserve any NT_GNU_BUILD_ATTRIBUTE_FUNC notes. 3. Eliminate any NT_GNU_BUILD_ATTRIBUTE_OPEN notes that have the same full name field as the immediately preceeding - note with the same type of name. + note with the same type of name and whoes address ranges + coincide. 4. Combine the numeric value of any NT_GNU_BUILD_ATTRIBUTE_OPEN notes of type GNU_BUILD_ATTRIBUTE_STACK_SIZE. 5. If an NT_GNU_BUILD_ATTRIBUTE_OPEN note is going to be @@ -195,3 +209,4 @@ ToDo: Check if -grecord-gcc-switches preserved per-translation-unit info after linking. + Handle -ffunction-sections. diff --git a/plugin/aarch64.annobin.cc b/plugin/aarch64.annobin.cc index b88ea59..ae6272e 100644 --- a/plugin/aarch64.annobin.cc +++ b/plugin/aarch64.annobin.cc @@ -32,12 +32,12 @@ annobin_record_global_target_notes (void) saved_tls_dialect = aarch64_tls_dialect; annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, saved_tls_dialect, - "numeric: ABI: TLS dialect", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "numeric: ABI: TLS dialect", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); annobin_inform (1, "Recording global TLS dialect of %d", saved_tls_dialect); } void -annobin_target_specific_function_notes (void) +annobin_target_specific_function_notes (const char * aname, const char * aname_end) { if (saved_tls_dialect == aarch64_tls_dialect) return; @@ -45,11 +45,9 @@ annobin_target_specific_function_notes (void) annobin_inform (1, "TLS dialect has changed from %d to %d for %s", saved_tls_dialect, aarch64_tls_dialect, current_function_name ()); - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, aarch64_tls_dialect, - "numeric: ABI: TLS dialect", name, - NT_GNU_BUILD_ATTRIBUTE_FUNC); + annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, aarch64_tls_dialect, + "numeric: ABI: TLS dialect", aname, aname_end, + NT_GNU_BUILD_ATTRIBUTE_FUNC); } typedef struct diff --git a/plugin/annobin.cc b/plugin/annobin.cc index f21282e..1864c48 100644 --- a/plugin/annobin.cc +++ b/plugin/annobin.cc @@ -19,7 +19,7 @@ #include /* The version of the annotation specification supported by this plugin. */ -#define SPEC_VERSION 2 +#define SPEC_VERSION 3 /* Required by the GCC plugin API. */ int plugin_is_GPL_compatible; @@ -59,6 +59,7 @@ static bool annobin_enable_dynamic_notes = true; /* True if notes in the .gnu.build.attributes section should be produced. */ static bool annobin_enable_static_notes = true; +static unsigned int annobin_note_count = 0; static unsigned int global_GOWall_options = 0; static int global_stack_prot_option = -1; static int global_pic_option = -1; @@ -66,8 +67,9 @@ static int global_short_enums = -1; static char * compiler_version = NULL; static unsigned verbose_level = 0; static char * annobin_current_filename = NULL; -static unsigned char annobin_version = 2; /* NB. Keep in sync with version_string. */ -static const char * version_string = N_("Version 2"); +static char * annobin_current_endname = NULL; +static unsigned char annobin_version = 3; /* NB. Keep in sync with version_string below. */ +static const char * version_string = N_("Version 3"); static const char * help_string = N_("Supported options:\n\ disable Disable this plugin\n\ enable Enable this plugin\n\ @@ -149,6 +151,7 @@ init_annobin_current_filename (void) } annobin_current_filename = name; + annobin_current_endname = concat (annobin_current_filename, "_end", NULL); } void @@ -172,10 +175,15 @@ annobin_inform (unsigned level, const char * format, ...) } void -annobin_output_note (const void * name, unsigned namesz, bool name_is_string, +annobin_output_note (const char * name, + unsigned namesz, + bool name_is_string, const char * name_description, - const void * desc, unsigned descsz, bool desc_is_string, - unsigned type) + const char * desc1, + const char * desc2, + unsigned descsz, + bool desc_is_string, + unsigned type) { unsigned i; @@ -203,20 +211,59 @@ annobin_output_note (const void * name, unsigned namesz, bool name_is_string, else fprintf (asm_out_file, "\t.dc.l %u\t\t%s size of name\n", namesz, ASM_COMMENT_START); - if (desc == NULL) + if (desc1 == NULL) { if (descsz) - annobin_inform (0, "ICE: null desc with non-zero size"); + annobin_inform (0, "ICE: null desc1 with non-zero size"); + if (desc2 != NULL) + annobin_inform (0, "ICE: non-null desc2 with null desc1"); + fprintf (asm_out_file, "\t.dc.l 0\t\t%s no description\n", ASM_COMMENT_START); } else if (desc_is_string) { - if (descsz != (annobin_is_64bit ? 8 : 4)) - annobin_inform (0, "ICE: description string size (%d) not sizeof address 8/4", descsz); - fprintf (asm_out_file, "\t.dc.l %u\t\t%s descsz = sizeof (address)\n", descsz, ASM_COMMENT_START); + switch (descsz) + { + case 0: + annobin_inform (0, "ICE: zero descsz with string description"); + break; + case 4: + if (annobin_is_64bit || desc2 != NULL) + annobin_inform (0, "ICE: descz too small"); + if (desc1 == NULL) + annobin_inform (0, "ICE: descz too big"); + break; + case 8: + if (annobin_is_64bit) + { + if (desc2 != NULL) + annobin_inform (0, "ICE: descz too small"); + } + else + { + if (desc1 == NULL || desc2 == NULL) + annobin_inform (0, "ICE: descz too big"); + } + break; + case 16: + if (! annobin_is_64bit || desc1 == NULL || desc2 == NULL) + annobin_inform (0, "ICE: descz too big"); + break; + default: + annobin_inform (0, "ICE: description string size (%d) does not match address size", descsz); + break; + } + + fprintf (asm_out_file, "\t.dc.l %u%s%s descsz = sizeof (address%s)\n", + descsz, descsz < 10 ? "\t\t" : "\t", ASM_COMMENT_START, desc2 == NULL ? "" : "es"); } else - fprintf (asm_out_file, "\t.dc.l %u\t\t%s size of description\n", descsz, ASM_COMMENT_START); + { + if (desc2 != NULL) + annobin_inform (0, "ICE: second description not empty for non-string description"); + + fprintf (asm_out_file, "\t.dc.l %u\t\t%s size of description\n", descsz, ASM_COMMENT_START); + } fprintf (asm_out_file, "\t.dc.l %#x\t%s type = %s\n", type, ASM_COMMENT_START, type == NT_GNU_BUILD_ATTRIBUTE_OPEN ? "OPEN" : @@ -253,7 +300,7 @@ annobin_output_note (const void * name, unsigned namesz, bool name_is_string, } } - if (desc) + if (desc1) { if (desc_is_string) { @@ -261,9 +308,19 @@ annobin_output_note (const void * name, unsigned namesz, bool name_is_string, a reference to this symbol of the appropriate size for the target architecture. */ if (annobin_is_64bit) - fprintf (asm_out_file, "\t.quad %s", (char *) desc); + fprintf (asm_out_file, "\t.quad %s", (char *) desc1); else - fprintf (asm_out_file, "\t.dc.l %s", (char *) desc); + fprintf (asm_out_file, "\t.dc.l %s", (char *) desc1); + + if (desc2) + { + fprintf (asm_out_file, "\n"); + if (annobin_is_64bit) + fprintf (asm_out_file, "\t.quad %s", (char *) desc2); + else + fprintf (asm_out_file, "\t.dc.l %s", (char *) desc2); + } + fprintf (asm_out_file, "\t%s description (symbol name)\n", ASM_COMMENT_START); } else @@ -272,7 +329,7 @@ annobin_output_note (const void * name, unsigned namesz, bool name_is_string, for (i = 0; i < descsz; i++) { - fprintf (asm_out_file, " %#x", ((unsigned char *) desc)[i]); + fprintf (asm_out_file, " %#x", ((unsigned char *) desc1)[i]); if (i == (descsz - 1)) fprintf (asm_out_file, "\t%s description\n", ASM_COMMENT_START); else if ((i % 8) == 7) @@ -302,13 +359,16 @@ annobin_output_note (const void * name, unsigned namesz, bool name_is_string, } fprintf (asm_out_file, "\n"); + + ++ annobin_note_count; } void annobin_output_bool_note (const char bool_type, const bool bool_value, const char * name_description, - const char * description, + const char * start, + const char * end, unsigned note_type) { char buffer [6]; @@ -320,15 +380,17 @@ annobin_output_bool_note (const char bool_type, /* Include the NUL byte at the end of the name "string". This is required by the ELF spec. */ annobin_output_note (buffer, strlen (buffer) + 1, false, name_description, - description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4), - description != NULL, note_type); + start, end, + start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4: 8)), + true, note_type); } void annobin_output_string_note (const char string_type, const char * string, const char * name_description, - const char * description, + const char * start, + const char * end, unsigned note_type) { unsigned int len = strlen (string); @@ -339,15 +401,17 @@ annobin_output_string_note (const char string_type, sprintf (buffer, "GA%c%c%s", GNU_BUILD_ATTRIBUTE_TYPE_STRING, string_type, string); annobin_output_note (buffer, len + 5, true, name_description, - description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4), - description != NULL, note_type); + start, end, + start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4 : 8)), + true, note_type); } void annobin_output_numeric_note (const char numeric_type, unsigned long value, const char * name_description, - const char * description, + const char * start, + const char * end, unsigned note_type) { unsigned i; @@ -385,8 +449,9 @@ annobin_output_numeric_note (const char numeric_type, annobin_inform (0, "ICE: Unable to record numeric value in note %s\n", name_description); annobin_output_note (buffer, i + 1, false, name_description, - description, description == NULL ? 0 : (annobin_is_64bit ? 8 : 4), true, - note_type); + start, end, + start == NULL ? 0 : (annobin_is_64bit ? (end == NULL ? 8 : 16) : (end == NULL ? 4 : 8)), + true, note_type); } static int @@ -474,7 +539,7 @@ compute_GOWall_options (void) } static void -record_GOW_settings (unsigned int gow, bool local) +record_GOW_settings (unsigned int gow, bool local, const char * cname, const char * aname, const char * aname_end) { char buffer [128]; unsigned i; @@ -494,80 +559,113 @@ record_GOW_settings (unsigned int gow, bool local) if (local) { - annobin_inform (1, "Record a change in -g/-O/-Wall status for %s", current_function_name ()); - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall", - name, annobin_is_64bit ? 8 : 4, true, - NT_GNU_BUILD_ATTRIBUTE_FUNC); + annobin_inform (1, "Record a change in -g/-O/-Wall status for %s", cname); + annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall", + aname, aname_end, annobin_is_64bit ? 16 : 8, true, + NT_GNU_BUILD_ATTRIBUTE_FUNC); } else { annobin_inform (1, "Record status of -g/-O/-Wall"); annobin_output_note (buffer, i + 1, false, "numeric: -g/-O/-Wall", - NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN); + NULL, NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN); } } static void annobin_create_function_notes (void * gcc_data, void * user_data) { + const char * cname = current_function_name (); + const char * aname = function_asm_name (); + const char * aname_end; + const char * saved_aname_end; + unsigned int count; + if (! annobin_enable_static_notes) return; if (asm_out_file == NULL) return; - annobin_target_specific_function_notes (); + if (cname == NULL) + { + if (aname == NULL) + { + /* Can this happen ? */ + annobin_inform (0, "ICE: function name not available"); + return; + } + cname = aname; + } + else if (aname == NULL) + aname = cname; + + saved_aname_end = aname_end = concat (aname, "_end", NULL); + count = annobin_note_count; + + annobin_target_specific_function_notes (aname, aname_end); + + if (count > annobin_note_count) + { + free ((void *) aname_end); + aname = aname_end = NULL; + } if (global_stack_prot_option != flag_stack_protect) { annobin_inform (1, "Recording change in stack protection status for %s (from %d to %d)", - current_function_name (), global_stack_prot_option, flag_stack_protect); + cname, global_stack_prot_option, flag_stack_protect); + + annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, flag_stack_protect, + "numeric: -fstack-protector status", + aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC); - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, flag_stack_protect, - "numeric: -fstack-protector status", - name, NT_GNU_BUILD_ATTRIBUTE_FUNC); + if (aname != NULL) + aname = aname_end = NULL; } if (global_pic_option != compute_pic_option ()) { - annobin_inform (1, "Recording change in PIC status for %s", current_function_name ()); - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, compute_pic_option (), - "numeric: pic type", name, - NT_GNU_BUILD_ATTRIBUTE_FUNC); + annobin_inform (1, "Recording change in PIC status for %s", cname); + annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, compute_pic_option (), + "numeric: pic type", aname, aname_end, + NT_GNU_BUILD_ATTRIBUTE_FUNC); + if (aname != NULL) + aname = aname_end = NULL; } if (global_GOWall_options != compute_GOWall_options ()) - record_GOW_settings (compute_GOWall_options (), true); + { + record_GOW_settings (compute_GOWall_options (), true, cname, aname, aname_end); + + if (aname != NULL) + aname = aname_end = NULL; + } if (global_short_enums != flag_short_enums) { - annobin_inform (1, "Recording change in enum size for %s", current_function_name ()); - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, flag_short_enums, - flag_short_enums ? "bool: short-enums: on" : "bool: short-enums: off", - name, NT_GNU_BUILD_ATTRIBUTE_FUNC); + annobin_inform (1, "Recording change in enum size for %s", cname); + annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, flag_short_enums, + flag_short_enums ? "bool: short-enums: on" : "bool: short-enums: off", + aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC); + if (aname != NULL) + aname = aname_end = NULL; } - if (annobin_enable_stack_size_notes && flag_stack_usage_info) { if ((unsigned long) current_function_static_stack_size > stack_threshold) { annobin_inform (1, "Recording stack usage of %lu for %s", - current_function_static_stack_size, current_function_name ()); - - const char *name = function_asm_name (); - if (name != NULL) - annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, current_function_static_stack_size, - "numeric: stack-size", name, - NT_GNU_BUILD_ATTRIBUTE_FUNC); + current_function_static_stack_size, cname); + + annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, + current_function_static_stack_size, + "numeric: stack-size", + aname, aname_end, + NT_GNU_BUILD_ATTRIBUTE_FUNC); + if (aname != NULL) + aname = aname_end = NULL; } annobin_total_static_stack_usage += current_function_static_stack_size; @@ -575,6 +673,16 @@ annobin_create_function_notes (void * gcc_data, void * user_data) if ((unsigned long) current_function_static_stack_size > annobin_max_stack_size) annobin_max_stack_size = current_function_static_stack_size; } + + if (annobin_note_count > count) + { + // /* FIXME: This assumes that the function is in the .text section... */ + // fprintf (asm_out_file, "\t.pushsection .text\n"); + fprintf (asm_out_file, "%s:\n", saved_aname_end); + // fprintf (asm_out_file, "\t.popsection\n"); + } + + free ((void *) saved_aname_end); } static void @@ -586,7 +694,7 @@ record_fortify_level (int level) buffer[++len] = level; buffer[++len] = 0; annobin_output_note (buffer, len + 1, false, "FORTIFY SOURCE level", - NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN); + NULL, NULL, 0, false, NT_GNU_BUILD_ATTRIBUTE_OPEN); annobin_inform (1, "Record a FORTIFY SOURCE level of %d", level); } @@ -647,9 +755,11 @@ annobin_create_global_notes (void * gcc_data, void * user_data) annobin_current_filename = (char *) "unknown_source"; } + /* Create a symbol for this compilation unit. */ if (global_file_name_symbols) fprintf (asm_out_file, ".global %s\n", annobin_current_filename); fprintf (asm_out_file, ".type %s STT_OBJECT\n", annobin_current_filename); + fprintf (asm_out_file, ".size %s, %s - %s\n",annobin_current_filename, annobin_current_endname, annobin_current_filename); fprintf (asm_out_file, "%s:\n", annobin_current_filename); /* Create the static notes section. */ @@ -666,19 +776,22 @@ annobin_create_global_notes (void * gcc_data, void * user_data) /* Output the version of the specification supported. */ sprintf (buffer, "%dp%d", SPEC_VERSION, annobin_version); annobin_output_string_note (GNU_BUILD_ATTRIBUTE_VERSION, buffer, - "string: version", annobin_current_filename, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "string: version", + annobin_current_filename, + annobin_current_endname, + NT_GNU_BUILD_ATTRIBUTE_OPEN); /* Record the version of the compiler. */ annobin_output_string_note (GNU_BUILD_ATTRIBUTE_TOOL, compiler_version, - "string: build-tool", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "string: build-tool", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); /* Record optimization level, -W setting and -g setting */ - record_GOW_settings (global_GOWall_options, false); + record_GOW_settings (global_GOWall_options, false, NULL, NULL, NULL); /* Record -fstack-protector option. */ annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_PROT, global_stack_prot_option, "numeric: -fstack-protector status", - NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); /* Look for -D _FORTIFY_SOURCE= on the original gcc command line. Scan backwards so that we record the last version of the option, @@ -716,12 +829,12 @@ annobin_create_global_notes (void * gcc_data, void * user_data) /* Record the PIC status. */ annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_PIC, global_pic_option, - "numeric: PIC", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "numeric: PIC", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); /* Record enum size. */ annobin_output_bool_note (GNU_BUILD_ATTRIBUTE_SHORT_ENUM, global_short_enums, global_short_enums ? "bool: short-enums: on" : "bool: short-enums: off", - NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); /* Record target specific notes. */ annobin_record_global_target_notes (); @@ -733,10 +846,15 @@ annobin_create_global_notes (void * gcc_data, void * user_data) static void annobin_create_loader_notes (void * gcc_data, void * user_data) { - if (! annobin_enable_dynamic_notes) + if (asm_out_file == NULL) return; - if (asm_out_file == NULL) + /* FIXME: This assumes that functions are being placed into the .text section. */ + fprintf (asm_out_file, "\t.pushsection .text\n"); + fprintf (asm_out_file, "%s:\n", annobin_current_endname); + fprintf (asm_out_file, "\t.popsection\n"); + + if (! annobin_enable_dynamic_notes) return; if (annobin_enable_stack_size_notes && annobin_total_static_stack_usage) @@ -745,7 +863,7 @@ annobin_create_loader_notes (void * gcc_data, void * user_data) fprintf (asm_out_file, "\t.pushsection %s\n", GNU_BUILD_ATTRS_SECTION_NAME); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_STACK_SIZE, annobin_total_static_stack_usage, - "numeric: stack-size", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "numeric: stack-size", NULL, NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); fprintf (asm_out_file, "\t.popsection\n"); } diff --git a/plugin/annobin.h b/plugin/annobin.h index 1957c94..e1b9e14 100644 --- a/plugin/annobin.h +++ b/plugin/annobin.h @@ -79,9 +79,11 @@ extern void annobin_save_target_specific_information (void); extern void annobin_record_global_target_notes (void); /* Called during PLUGIN_ALL_PASSES_END. + Should produce notes specific to the function just compiled. Should only produce notes for the static tools, ie - notes in the .gnu.build.attributes section. */ -extern void annobin_target_specific_function_notes (void); + notes in the .gnu.build.attributes section. + Arguments are the start and end symbols for the function. */ +extern void annobin_target_specific_function_notes (const char *, const char *); /* Called during PLUGIN_FINISH_UNIT. Should only produce notes for the dynamic loader, ie @@ -89,10 +91,10 @@ extern void annobin_target_specific_function_notes (void); extern void annobin_target_specific_loader_notes (void); extern void annobin_inform (unsigned, const char *, ...); -extern void annobin_output_note (const void *, unsigned, bool, const char *, const void *, unsigned, bool, unsigned); -extern void annobin_output_bool_note (const char , const bool, const char *, const char *, unsigned); -extern void annobin_output_string_note (const char, const char *, const char *, const char *, unsigned); -extern void annobin_output_numeric_note (const char, unsigned long, const char *, const char *, unsigned); +extern void annobin_output_note (const char *, unsigned, bool, const char *, const char *, const char *, unsigned, bool, unsigned); +extern void annobin_output_bool_note (const char, const bool, const char *, const char *, const char *, unsigned); +extern void annobin_output_string_note (const char, const char *, const char *, const char *, const char *, unsigned); +extern void annobin_output_numeric_note (const char, unsigned long, const char *, const char *, const char *, unsigned); extern bool annobin_is_64bit; extern bool annobin_enable_stack_size_notes; diff --git a/plugin/dummy.annobin.cc b/plugin/dummy.annobin.cc index f58681e..4c463cc 100644 --- a/plugin/dummy.annobin.cc +++ b/plugin/dummy.annobin.cc @@ -33,7 +33,7 @@ annobin_record_global_target_notes (void) } void -annobin_target_specific_function_notes (void) +annobin_target_specific_function_notes (const char * aname, const char * aname_end) { } diff --git a/plugin/powerpc.annobin.cc b/plugin/powerpc.annobin.cc index 0057920..49f583c 100644 --- a/plugin/powerpc.annobin.cc +++ b/plugin/powerpc.annobin.cc @@ -31,25 +31,22 @@ annobin_record_global_target_notes (void) saved_tls_size = rs6000_tls_size; annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, saved_tls_size, - "numeric: ABI: TLS size", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "numeric: ABI: TLS size", NULL, NULL, + NT_GNU_BUILD_ATTRIBUTE_OPEN); annobin_inform (1, "Recording global TLS size of %d", saved_tls_size); } void -annobin_target_specific_function_notes (void) +annobin_target_specific_function_notes (const char * aname, const char * aname_end) { if (saved_tls_size == rs6000_tls_size) return; - const char *name = function_asm_name (); - if (name == NULL) - return; - annobin_inform (1, "TLS size has changed from %d to %d for %s", - saved_tls_size, rs6000_tls_size, name); + saved_tls_size, rs6000_tls_size, aname); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, rs6000_tls_size, - "numeric: ABI: TLS size", name, + "numeric: ABI: TLS size", aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC); } diff --git a/plugin/x86_64.annobin.cc b/plugin/x86_64.annobin.cc index a03fe94..3fc5b9c 100644 --- a/plugin/x86_64.annobin.cc +++ b/plugin/x86_64.annobin.cc @@ -56,23 +56,21 @@ annobin_record_global_target_notes (void) min_x86_isa = max_x86_isa = global_x86_isa = ix86_isa_flags; annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, global_x86_isa, - "numeric: ABI", NULL, NT_GNU_BUILD_ATTRIBUTE_OPEN); + "numeric: ABI", NULL, NULL, + NT_GNU_BUILD_ATTRIBUTE_OPEN); annobin_inform (1, "Record global isa of %lx", global_x86_isa); } void -annobin_target_specific_function_notes (void) +annobin_target_specific_function_notes (const char * aname, const char * aname_end) { - const char *name = function_asm_name (); - if (name == NULL) - return; if ((unsigned long) ix86_isa_flags != global_x86_isa) { annobin_inform (1, "ISA value has changed from %lx to %lx for %s", - global_x86_isa, ix86_isa_flags, name); + global_x86_isa, ix86_isa_flags, aname); annobin_output_numeric_note (GNU_BUILD_ATTRIBUTE_ABI, ix86_isa_flags, - "numeric: ABI", name, + "numeric: ABI", aname, aname_end, NT_GNU_BUILD_ATTRIBUTE_FUNC); if ((unsigned long) ix86_isa_flags < min_x86_isa) @@ -208,7 +206,7 @@ annobin_target_specific_loader_notes (void) ptr += sizeof (note32); } - annobin_output_note ("GNU", 4, true, "Loader notes", buffer, ptr - buffer, + annobin_output_note ("GNU", 4, true, "Loader notes", buffer, NULL, ptr - buffer, false, NT_GNU_PROPERTY_TYPE_0); fflush (asm_out_file); } diff --git a/tests/Makefile.am b/tests/Makefile.am index 54f555d..8b75058 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,6 +6,6 @@ ## Process this file with automake to produce Makefile.in. -TESTS=compile-test hardening-test hardening-fail-test abi-test +TESTS=compile-test hardening-test hardening-fail-test abi-test missing-notes-test XFAIL_TESTS=hardening-fail-test diff --git a/tests/Makefile.in b/tests/Makefile.in index f74caee..11e79dc 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -211,7 +211,7 @@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -TESTS = compile-test hardening-test hardening-fail-test abi-test +TESTS = compile-test hardening-test hardening-fail-test abi-test missing-notes-test XFAIL_TESTS = hardening-fail-test all: all-am diff --git a/tests/hello.c b/tests/hello.c index b3db10e..b4211b5 100644 --- a/tests/hello.c +++ b/tests/hello.c @@ -5,6 +5,12 @@ extern int big_stack (int); int baz (void) __attribute__((optimize("-O0"),__noinline__)); int bar (void) __attribute__((optimize("-fstack-protector-strong"),__noinline__)); +int +ordinary_func (void) +{ + return 77; +} + int bar (void) { diff --git a/tests/missing-notes-test b/tests/missing-notes-test new file mode 100755 index 0000000..340390e --- /dev/null +++ b/tests/missing-notes-test @@ -0,0 +1,50 @@ +#!/bin/bash + +# Copyright (c) 2017 Red Hat. +# +# This 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, or (at your +# option) any later version. +# +# It 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. + +rm -f hello.o hello2.o hello3.o libhello.so compile-test.exe + +GCC=gcc +READELF=readelf +OBJCOPY=objcopy + +PLUGIN=../plugin/.libs/annobin.so + +$GCC -fplugin=$PLUGIN \ + -c \ + -fPIC \ + -fno-stack-protector \ + $srcdir/hello.c + +$GCC -O3 \ + -c \ + -fPIC \ + $srcdir/hello2.c + +$GCC -fplugin=$PLUGIN \ + -c \ + -fPIC \ + $srcdir/hello3.c \ + +$GCC -fplugin=$PLUGIN \ + -fPIC \ + -shared \ + $srcdir/hello_lib.c \ + -o libhello.so + +$GCC -fplugin=$PLUGIN \ + -L . \ + hello.o hello2.o hello3.o -lhello -o missing-notes-test.exe + +# FIXME - we should check that the notes were parsed correctly... +$READELF --notes --wide missing-notes-test.exe > /dev/null -- 2.43.5