Commit 8cbce376e3fdf4a21f59365aefbb52eac3c2e312
Committed by
Linus Torvalds
1 parent
0d20633b04
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
gcov: move gcov structs definitions to a gcc version specific file
Since also the gcov structures(gcov_info, gcov_fn_info, gcov_ctr_info) can change between gcc releases, as shown in gcc 4.7, they cannot be defined in a common header and need to be moved to a specific gcc implemention file. This also requires to make the gcov_info structure opaque for the common code and to introduce simple helpers for accessing data inside gcov_info. Signed-off-by: Frantisek Hrbata <fhrbata@redhat.com> Cc: Jan Stancek <jstancek@redhat.com> Cc: Kees Cook <keescook@chromium.org> Acked-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Andy Gospodarek <agospoda@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 4 changed files with 153 additions and 80 deletions Side-by-side Diff
kernel/gcov/base.c
... | ... | @@ -20,7 +20,6 @@ |
20 | 20 | #include <linux/mutex.h> |
21 | 21 | #include "gcov.h" |
22 | 22 | |
23 | -static struct gcov_info *gcov_info_head; | |
24 | 23 | static int gcov_events_enabled; |
25 | 24 | static DEFINE_MUTEX(gcov_lock); |
26 | 25 | |
... | ... | @@ -34,7 +33,7 @@ |
34 | 33 | |
35 | 34 | mutex_lock(&gcov_lock); |
36 | 35 | if (gcov_version == 0) { |
37 | - gcov_version = info->version; | |
36 | + gcov_version = gcov_info_version(info); | |
38 | 37 | /* |
39 | 38 | * Printing gcc's version magic may prove useful for debugging |
40 | 39 | * incompatibility reports. |
... | ... | @@ -45,8 +44,7 @@ |
45 | 44 | * Add new profiling data structure to list and inform event |
46 | 45 | * listener. |
47 | 46 | */ |
48 | - info->next = gcov_info_head; | |
49 | - gcov_info_head = info; | |
47 | + gcov_info_link(info); | |
50 | 48 | if (gcov_events_enabled) |
51 | 49 | gcov_event(GCOV_ADD, info); |
52 | 50 | mutex_unlock(&gcov_lock); |
53 | 51 | |
54 | 52 | |
55 | 53 | |
... | ... | @@ -91,13 +89,15 @@ |
91 | 89 | */ |
92 | 90 | void gcov_enable_events(void) |
93 | 91 | { |
94 | - struct gcov_info *info; | |
92 | + struct gcov_info *info = NULL; | |
95 | 93 | |
96 | 94 | mutex_lock(&gcov_lock); |
97 | 95 | gcov_events_enabled = 1; |
96 | + | |
98 | 97 | /* Perform event callback for previously registered entries. */ |
99 | - for (info = gcov_info_head; info; info = info->next) | |
98 | + while ((info = gcov_info_next(info))) | |
100 | 99 | gcov_event(GCOV_ADD, info); |
100 | + | |
101 | 101 | mutex_unlock(&gcov_lock); |
102 | 102 | } |
103 | 103 | |
104 | 104 | |
105 | 105 | |
106 | 106 | |
107 | 107 | |
... | ... | @@ -112,25 +112,23 @@ |
112 | 112 | void *data) |
113 | 113 | { |
114 | 114 | struct module *mod = data; |
115 | - struct gcov_info *info; | |
116 | - struct gcov_info *prev; | |
115 | + struct gcov_info *info = NULL; | |
116 | + struct gcov_info *prev = NULL; | |
117 | 117 | |
118 | 118 | if (event != MODULE_STATE_GOING) |
119 | 119 | return NOTIFY_OK; |
120 | 120 | mutex_lock(&gcov_lock); |
121 | - prev = NULL; | |
121 | + | |
122 | 122 | /* Remove entries located in module from linked list. */ |
123 | - for (info = gcov_info_head; info; info = info->next) { | |
123 | + while ((info = gcov_info_next(info))) { | |
124 | 124 | if (within(info, mod->module_core, mod->core_size)) { |
125 | - if (prev) | |
126 | - prev->next = info->next; | |
127 | - else | |
128 | - gcov_info_head = info->next; | |
125 | + gcov_info_unlink(prev, info); | |
129 | 126 | if (gcov_events_enabled) |
130 | 127 | gcov_event(GCOV_REMOVE, info); |
131 | 128 | } else |
132 | 129 | prev = info; |
133 | 130 | } |
131 | + | |
134 | 132 | mutex_unlock(&gcov_lock); |
135 | 133 | |
136 | 134 | return NOTIFY_OK; |
kernel/gcov/fs.c
... | ... | @@ -242,7 +242,7 @@ |
242 | 242 | |
243 | 243 | list_for_each_entry(node, &all_head, all) { |
244 | 244 | info = get_node_info(node); |
245 | - if (info && (strcmp(info->filename, name) == 0)) | |
245 | + if (info && (strcmp(gcov_info_filename(info), name) == 0)) | |
246 | 246 | return node; |
247 | 247 | } |
248 | 248 | |
... | ... | @@ -279,7 +279,7 @@ |
279 | 279 | seq = file->private_data; |
280 | 280 | info = gcov_iter_get_info(seq->private); |
281 | 281 | mutex_lock(&node_lock); |
282 | - node = get_node_by_name(info->filename); | |
282 | + node = get_node_by_name(gcov_info_filename(info)); | |
283 | 283 | if (node) { |
284 | 284 | /* Reset counts or remove node for unloaded modules. */ |
285 | 285 | if (node->num_loaded == 0) |
... | ... | @@ -376,8 +376,9 @@ |
376 | 376 | if (!node->links) |
377 | 377 | return; |
378 | 378 | for (i = 0; i < num; i++) { |
379 | - target = get_link_target(get_node_info(node)->filename, | |
380 | - &gcov_link[i]); | |
379 | + target = get_link_target( | |
380 | + gcov_info_filename(get_node_info(node)), | |
381 | + &gcov_link[i]); | |
381 | 382 | if (!target) |
382 | 383 | goto out_err; |
383 | 384 | basename = strrchr(target, '/'); |
... | ... | @@ -576,7 +577,7 @@ |
576 | 577 | struct gcov_node *parent; |
577 | 578 | struct gcov_node *node; |
578 | 579 | |
579 | - filename = kstrdup(info->filename, GFP_KERNEL); | |
580 | + filename = kstrdup(gcov_info_filename(info), GFP_KERNEL); | |
580 | 581 | if (!filename) |
581 | 582 | return; |
582 | 583 | parent = &root_node; |
... | ... | @@ -631,7 +632,7 @@ |
631 | 632 | loaded_info = kcalloc(num + 1, sizeof(struct gcov_info *), GFP_KERNEL); |
632 | 633 | if (!loaded_info) { |
633 | 634 | pr_warning("could not add '%s' (out of memory)\n", |
634 | - info->filename); | |
635 | + gcov_info_filename(info)); | |
635 | 636 | return; |
636 | 637 | } |
637 | 638 | memcpy(loaded_info, node->loaded_info, |
... | ... | @@ -645,7 +646,8 @@ |
645 | 646 | */ |
646 | 647 | if (!gcov_info_is_compatible(node->unloaded_info, info)) { |
647 | 648 | pr_warning("discarding saved data for %s " |
648 | - "(incompatible version)\n", info->filename); | |
649 | + "(incompatible version)\n", | |
650 | + gcov_info_filename(info)); | |
649 | 651 | gcov_info_free(node->unloaded_info); |
650 | 652 | node->unloaded_info = NULL; |
651 | 653 | } |
... | ... | @@ -656,7 +658,7 @@ |
656 | 658 | */ |
657 | 659 | if (!gcov_info_is_compatible(node->loaded_info[0], info)) { |
658 | 660 | pr_warning("could not add '%s' (incompatible " |
659 | - "version)\n", info->filename); | |
661 | + "version)\n", gcov_info_filename(info)); | |
660 | 662 | kfree(loaded_info); |
661 | 663 | return; |
662 | 664 | } |
... | ... | @@ -692,7 +694,8 @@ |
692 | 694 | node->unloaded_info = gcov_info_dup(info); |
693 | 695 | if (!node->unloaded_info) { |
694 | 696 | pr_warning("could not save data for '%s' " |
695 | - "(out of memory)\n", info->filename); | |
697 | + "(out of memory)\n", | |
698 | + gcov_info_filename(info)); | |
696 | 699 | } |
697 | 700 | } |
698 | 701 | } |
... | ... | @@ -708,7 +711,7 @@ |
708 | 711 | i = get_info_index(node, info); |
709 | 712 | if (i < 0) { |
710 | 713 | pr_warning("could not remove '%s' (not found)\n", |
711 | - info->filename); | |
714 | + gcov_info_filename(info)); | |
712 | 715 | return; |
713 | 716 | } |
714 | 717 | if (gcov_persist) |
... | ... | @@ -735,7 +738,7 @@ |
735 | 738 | struct gcov_node *node; |
736 | 739 | |
737 | 740 | mutex_lock(&node_lock); |
738 | - node = get_node_by_name(info->filename); | |
741 | + node = get_node_by_name(gcov_info_filename(info)); | |
739 | 742 | switch (action) { |
740 | 743 | case GCOV_ADD: |
741 | 744 | if (node) |
... | ... | @@ -748,7 +751,7 @@ |
748 | 751 | remove_info(node, info); |
749 | 752 | else { |
750 | 753 | pr_warning("could not remove '%s' (not found)\n", |
751 | - info->filename); | |
754 | + gcov_info_filename(info)); | |
752 | 755 | } |
753 | 756 | break; |
754 | 757 | } |
kernel/gcov/gcc_3_4.c
... | ... | @@ -21,6 +21,121 @@ |
21 | 21 | #include <linux/vmalloc.h> |
22 | 22 | #include "gcov.h" |
23 | 23 | |
24 | +#define GCOV_COUNTERS 5 | |
25 | + | |
26 | +static struct gcov_info *gcov_info_head; | |
27 | + | |
28 | +/** | |
29 | + * struct gcov_fn_info - profiling meta data per function | |
30 | + * @ident: object file-unique function identifier | |
31 | + * @checksum: function checksum | |
32 | + * @n_ctrs: number of values per counter type belonging to this function | |
33 | + * | |
34 | + * This data is generated by gcc during compilation and doesn't change | |
35 | + * at run-time. | |
36 | + */ | |
37 | +struct gcov_fn_info { | |
38 | + unsigned int ident; | |
39 | + unsigned int checksum; | |
40 | + unsigned int n_ctrs[0]; | |
41 | +}; | |
42 | + | |
43 | +/** | |
44 | + * struct gcov_ctr_info - profiling data per counter type | |
45 | + * @num: number of counter values for this type | |
46 | + * @values: array of counter values for this type | |
47 | + * @merge: merge function for counter values of this type (unused) | |
48 | + * | |
49 | + * This data is generated by gcc during compilation and doesn't change | |
50 | + * at run-time with the exception of the values array. | |
51 | + */ | |
52 | +struct gcov_ctr_info { | |
53 | + unsigned int num; | |
54 | + gcov_type *values; | |
55 | + void (*merge)(gcov_type *, unsigned int); | |
56 | +}; | |
57 | + | |
58 | +/** | |
59 | + * struct gcov_info - profiling data per object file | |
60 | + * @version: gcov version magic indicating the gcc version used for compilation | |
61 | + * @next: list head for a singly-linked list | |
62 | + * @stamp: time stamp | |
63 | + * @filename: name of the associated gcov data file | |
64 | + * @n_functions: number of instrumented functions | |
65 | + * @functions: function data | |
66 | + * @ctr_mask: mask specifying which counter types are active | |
67 | + * @counts: counter data per counter type | |
68 | + * | |
69 | + * This data is generated by gcc during compilation and doesn't change | |
70 | + * at run-time with the exception of the next pointer. | |
71 | + */ | |
72 | +struct gcov_info { | |
73 | + unsigned int version; | |
74 | + struct gcov_info *next; | |
75 | + unsigned int stamp; | |
76 | + const char *filename; | |
77 | + unsigned int n_functions; | |
78 | + const struct gcov_fn_info *functions; | |
79 | + unsigned int ctr_mask; | |
80 | + struct gcov_ctr_info counts[0]; | |
81 | +}; | |
82 | + | |
83 | +/** | |
84 | + * gcov_info_filename - return info filename | |
85 | + * @info: profiling data set | |
86 | + */ | |
87 | +const char *gcov_info_filename(struct gcov_info *info) | |
88 | +{ | |
89 | + return info->filename; | |
90 | +} | |
91 | + | |
92 | +/** | |
93 | + * gcov_info_version - return info version | |
94 | + * @info: profiling data set | |
95 | + */ | |
96 | +unsigned int gcov_info_version(struct gcov_info *info) | |
97 | +{ | |
98 | + return info->version; | |
99 | +} | |
100 | + | |
101 | +/** | |
102 | + * gcov_info_next - return next profiling data set | |
103 | + * @info: profiling data set | |
104 | + * | |
105 | + * Returns next gcov_info following @info or first gcov_info in the chain if | |
106 | + * @info is %NULL. | |
107 | + */ | |
108 | +struct gcov_info *gcov_info_next(struct gcov_info *info) | |
109 | +{ | |
110 | + if (!info) | |
111 | + return gcov_info_head; | |
112 | + | |
113 | + return info->next; | |
114 | +} | |
115 | + | |
116 | +/** | |
117 | + * gcov_info_link - link/add profiling data set to the list | |
118 | + * @info: profiling data set | |
119 | + */ | |
120 | +void gcov_info_link(struct gcov_info *info) | |
121 | +{ | |
122 | + info->next = gcov_info_head; | |
123 | + gcov_info_head = info; | |
124 | +} | |
125 | + | |
126 | +/** | |
127 | + * gcov_info_unlink - unlink/remove profiling data set from the list | |
128 | + * @prev: previous profiling data set | |
129 | + * @info: profiling data set | |
130 | + */ | |
131 | +void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info) | |
132 | +{ | |
133 | + if (prev) | |
134 | + prev->next = info->next; | |
135 | + else | |
136 | + gcov_info_head = info->next; | |
137 | +} | |
138 | + | |
24 | 139 | /* Symbolic links to be created for each profiling data file. */ |
25 | 140 | const struct gcov_link gcov_link[] = { |
26 | 141 | { OBJ_TREE, "gcno" }, /* Link to .gcno file in $(objtree). */ |
kernel/gcov/gcov.h
... | ... | @@ -21,7 +21,6 @@ |
21 | 21 | * gcc and need to be kept as close to the original definition as possible to |
22 | 22 | * remain compatible. |
23 | 23 | */ |
24 | -#define GCOV_COUNTERS 5 | |
25 | 24 | #define GCOV_DATA_MAGIC ((unsigned int) 0x67636461) |
26 | 25 | #define GCOV_TAG_FUNCTION ((unsigned int) 0x01000000) |
27 | 26 | #define GCOV_TAG_COUNTER_BASE ((unsigned int) 0x01a10000) |
28 | 27 | |
... | ... | @@ -34,60 +33,18 @@ |
34 | 33 | typedef long long gcov_type; |
35 | 34 | #endif |
36 | 35 | |
37 | -/** | |
38 | - * struct gcov_fn_info - profiling meta data per function | |
39 | - * @ident: object file-unique function identifier | |
40 | - * @checksum: function checksum | |
41 | - * @n_ctrs: number of values per counter type belonging to this function | |
42 | - * | |
43 | - * This data is generated by gcc during compilation and doesn't change | |
44 | - * at run-time. | |
45 | - */ | |
46 | -struct gcov_fn_info { | |
47 | - unsigned int ident; | |
48 | - unsigned int checksum; | |
49 | - unsigned int n_ctrs[0]; | |
50 | -}; | |
36 | +/* Opaque gcov_info. The gcov structures can change as for example in gcc 4.7 so | |
37 | + * we cannot use full definition here and they need to be placed in gcc specific | |
38 | + * implementation of gcov. This also means no direct access to the members in | |
39 | + * generic code and usage of the interface below.*/ | |
40 | +struct gcov_info; | |
51 | 41 | |
52 | -/** | |
53 | - * struct gcov_ctr_info - profiling data per counter type | |
54 | - * @num: number of counter values for this type | |
55 | - * @values: array of counter values for this type | |
56 | - * @merge: merge function for counter values of this type (unused) | |
57 | - * | |
58 | - * This data is generated by gcc during compilation and doesn't change | |
59 | - * at run-time with the exception of the values array. | |
60 | - */ | |
61 | -struct gcov_ctr_info { | |
62 | - unsigned int num; | |
63 | - gcov_type *values; | |
64 | - void (*merge)(gcov_type *, unsigned int); | |
65 | -}; | |
66 | - | |
67 | -/** | |
68 | - * struct gcov_info - profiling data per object file | |
69 | - * @version: gcov version magic indicating the gcc version used for compilation | |
70 | - * @next: list head for a singly-linked list | |
71 | - * @stamp: time stamp | |
72 | - * @filename: name of the associated gcov data file | |
73 | - * @n_functions: number of instrumented functions | |
74 | - * @functions: function data | |
75 | - * @ctr_mask: mask specifying which counter types are active | |
76 | - * @counts: counter data per counter type | |
77 | - * | |
78 | - * This data is generated by gcc during compilation and doesn't change | |
79 | - * at run-time with the exception of the next pointer. | |
80 | - */ | |
81 | -struct gcov_info { | |
82 | - unsigned int version; | |
83 | - struct gcov_info *next; | |
84 | - unsigned int stamp; | |
85 | - const char *filename; | |
86 | - unsigned int n_functions; | |
87 | - const struct gcov_fn_info *functions; | |
88 | - unsigned int ctr_mask; | |
89 | - struct gcov_ctr_info counts[0]; | |
90 | -}; | |
42 | +/* Interface to access gcov_info data */ | |
43 | +const char *gcov_info_filename(struct gcov_info *info); | |
44 | +unsigned int gcov_info_version(struct gcov_info *info); | |
45 | +struct gcov_info *gcov_info_next(struct gcov_info *info); | |
46 | +void gcov_info_link(struct gcov_info *info); | |
47 | +void gcov_info_unlink(struct gcov_info *prev, struct gcov_info *info); | |
91 | 48 | |
92 | 49 | /* Base interface. */ |
93 | 50 | enum gcov_action { |