diff options
author | Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> | 2016-08-30 04:39:37 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-09-01 11:42:26 -0400 |
commit | 6243b9dc4c991fe8bdc53a0e029908aef3ddb101 (patch) | |
tree | 2a658a69aeb5f1f82fa4240dff00283c05ba7ef4 | |
parent | e47392bf9c0613a058cd20ee89d8ce9d957d4b24 (diff) |
perf probe: Move dwarf specific functions to dwarf-aux.c
Move generic dwarf related functions from util/probe-finder.c to
util/dwarf-aux.c. Functions name and their prototype are also changed
accordingly. No functionality changes.
Suggested-and-Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Hemant Kumar <hemant@linux.vnet.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1472546377-25612-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 179 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.h | 8 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 136 |
3 files changed, 189 insertions, 134 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index a347b19c961a..faec899435f2 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, | |||
1085 | return -ENOTSUP; | 1085 | return -ENOTSUP; |
1086 | } | 1086 | } |
1087 | #endif | 1087 | #endif |
1088 | |||
1089 | /* | ||
1090 | * die_has_loclist - Check if DW_AT_location of @vr_die is a location list | ||
1091 | * @vr_die: a variable DIE | ||
1092 | */ | ||
1093 | static bool die_has_loclist(Dwarf_Die *vr_die) | ||
1094 | { | ||
1095 | Dwarf_Attribute loc; | ||
1096 | int tag = dwarf_tag(vr_die); | ||
1097 | |||
1098 | if (tag != DW_TAG_formal_parameter && | ||
1099 | tag != DW_TAG_variable) | ||
1100 | return false; | ||
1101 | |||
1102 | return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) && | ||
1103 | dwarf_whatform(&loc) == DW_FORM_sec_offset); | ||
1104 | } | ||
1105 | |||
1106 | /* | ||
1107 | * die_is_optimized_target - Check if target program is compiled with | ||
1108 | * optimization | ||
1109 | * @cu_die: a CU DIE | ||
1110 | * | ||
1111 | * For any object in given CU whose DW_AT_location is a location list, | ||
1112 | * target program is compiled with optimization. This is applicable to | ||
1113 | * clang as well. | ||
1114 | */ | ||
1115 | bool die_is_optimized_target(Dwarf_Die *cu_die) | ||
1116 | { | ||
1117 | Dwarf_Die tmp_die; | ||
1118 | |||
1119 | if (die_has_loclist(cu_die)) | ||
1120 | return true; | ||
1121 | |||
1122 | if (!dwarf_child(cu_die, &tmp_die) && | ||
1123 | die_is_optimized_target(&tmp_die)) | ||
1124 | return true; | ||
1125 | |||
1126 | if (!dwarf_siblingof(cu_die, &tmp_die) && | ||
1127 | die_is_optimized_target(&tmp_die)) | ||
1128 | return true; | ||
1129 | |||
1130 | return false; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | * die_search_idx - Search index of given line address | ||
1135 | * @lines: Line records of single CU | ||
1136 | * @nr_lines: Number of @lines | ||
1137 | * @addr: address we are looking for | ||
1138 | * @idx: index to be set by this function (return value) | ||
1139 | * | ||
1140 | * Search for @addr by looping over every lines of CU. If address | ||
1141 | * matches, set index of that line in @idx. Note that single source | ||
1142 | * line can have multiple line records. i.e. single source line can | ||
1143 | * have multiple index. | ||
1144 | */ | ||
1145 | static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines, | ||
1146 | Dwarf_Addr addr, unsigned long *idx) | ||
1147 | { | ||
1148 | unsigned long i; | ||
1149 | Dwarf_Addr tmp; | ||
1150 | |||
1151 | for (i = 0; i < nr_lines; i++) { | ||
1152 | if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp)) | ||
1153 | return false; | ||
1154 | |||
1155 | if (tmp == addr) { | ||
1156 | *idx = i; | ||
1157 | return true; | ||
1158 | } | ||
1159 | } | ||
1160 | return false; | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * die_get_postprologue_addr - Search next address after function prologue | ||
1165 | * @entrypc_idx: entrypc index | ||
1166 | * @lines: Line records of single CU | ||
1167 | * @nr_lines: Number of @lines | ||
1168 | * @hignpc: high PC address of function | ||
1169 | * @postprologue_addr: Next address after function prologue (return value) | ||
1170 | * | ||
1171 | * Look for prologue-end marker. If there is no explicit marker, return | ||
1172 | * address of next line record or next source line. | ||
1173 | */ | ||
1174 | static bool die_get_postprologue_addr(unsigned long entrypc_idx, | ||
1175 | Dwarf_Lines *lines, | ||
1176 | unsigned long nr_lines, | ||
1177 | Dwarf_Addr highpc, | ||
1178 | Dwarf_Addr *postprologue_addr) | ||
1179 | { | ||
1180 | unsigned long i; | ||
1181 | int entrypc_lno, lno; | ||
1182 | Dwarf_Line *line; | ||
1183 | Dwarf_Addr addr; | ||
1184 | bool p_end; | ||
1185 | |||
1186 | /* entrypc_lno is actual source line number */ | ||
1187 | line = dwarf_onesrcline(lines, entrypc_idx); | ||
1188 | if (dwarf_lineno(line, &entrypc_lno)) | ||
1189 | return false; | ||
1190 | |||
1191 | for (i = entrypc_idx; i < nr_lines; i++) { | ||
1192 | line = dwarf_onesrcline(lines, i); | ||
1193 | |||
1194 | if (dwarf_lineaddr(line, &addr) || | ||
1195 | dwarf_lineno(line, &lno) || | ||
1196 | dwarf_lineprologueend(line, &p_end)) | ||
1197 | return false; | ||
1198 | |||
1199 | /* highpc is exclusive. [entrypc,highpc) */ | ||
1200 | if (addr >= highpc) | ||
1201 | break; | ||
1202 | |||
1203 | /* clang supports prologue-end marker */ | ||
1204 | if (p_end) | ||
1205 | break; | ||
1206 | |||
1207 | /* Actual next line in source */ | ||
1208 | if (lno != entrypc_lno) | ||
1209 | break; | ||
1210 | |||
1211 | /* | ||
1212 | * Single source line can have multiple line records. | ||
1213 | * For Example, | ||
1214 | * void foo() { printf("hello\n"); } | ||
1215 | * contains two line records. One points to declaration and | ||
1216 | * other points to printf() line. Variable 'lno' won't get | ||
1217 | * incremented in this case but 'i' will. | ||
1218 | */ | ||
1219 | if (i != entrypc_idx) | ||
1220 | break; | ||
1221 | } | ||
1222 | |||
1223 | dwarf_lineaddr(line, postprologue_addr); | ||
1224 | if (*postprologue_addr >= highpc) | ||
1225 | dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), | ||
1226 | postprologue_addr); | ||
1227 | |||
1228 | return true; | ||
1229 | } | ||
1230 | |||
1231 | /* | ||
1232 | * die_skip_prologue - Use next address after prologue as probe location | ||
1233 | * @sp_die: a subprogram DIE | ||
1234 | * @cu_die: a CU DIE | ||
1235 | * @entrypc: entrypc of the function | ||
1236 | * | ||
1237 | * Function prologue prepares stack and registers before executing function | ||
1238 | * logic. When target program is compiled without optimization, function | ||
1239 | * parameter information is only valid after prologue. When we probe entrypc | ||
1240 | * of the function, and try to record function parameter, it contains | ||
1241 | * garbage value. | ||
1242 | */ | ||
1243 | void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, | ||
1244 | Dwarf_Addr *entrypc) | ||
1245 | { | ||
1246 | size_t nr_lines = 0; | ||
1247 | unsigned long entrypc_idx = 0; | ||
1248 | Dwarf_Lines *lines = NULL; | ||
1249 | Dwarf_Addr postprologue_addr; | ||
1250 | Dwarf_Addr highpc; | ||
1251 | |||
1252 | if (dwarf_highpc(sp_die, &highpc)) | ||
1253 | return; | ||
1254 | |||
1255 | if (dwarf_getsrclines(cu_die, &lines, &nr_lines)) | ||
1256 | return; | ||
1257 | |||
1258 | if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx)) | ||
1259 | return; | ||
1260 | |||
1261 | if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines, | ||
1262 | highpc, &postprologue_addr)) | ||
1263 | return; | ||
1264 | |||
1265 | *entrypc = postprologue_addr; | ||
1266 | } | ||
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index dc0ce1adb075..8b6d2f83af02 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf); | |||
125 | /* Get the name and type of given variable DIE, stored as "type\tname" */ | 125 | /* Get the name and type of given variable DIE, stored as "type\tname" */ |
126 | int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); | 126 | int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); |
127 | int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); | 127 | int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); |
128 | |||
129 | /* Check if target program is compiled with optimization */ | ||
130 | bool die_is_optimized_target(Dwarf_Die *cu_die); | ||
131 | |||
132 | /* Use next address after prologue as probe location */ | ||
133 | void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, | ||
134 | Dwarf_Addr *entrypc); | ||
135 | |||
128 | #endif | 136 | #endif |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 003ecadae35d..8daca4fc1f8d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -907,138 +907,6 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
907 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 907 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
908 | } | 908 | } |
909 | 909 | ||
910 | static bool var_has_loclist(Dwarf_Die *cu_die) | ||
911 | { | ||
912 | Dwarf_Attribute loc; | ||
913 | int tag = dwarf_tag(cu_die); | ||
914 | |||
915 | if (tag != DW_TAG_formal_parameter && | ||
916 | tag != DW_TAG_variable) | ||
917 | return false; | ||
918 | |||
919 | return (dwarf_attr_integrate(cu_die, DW_AT_location, &loc) && | ||
920 | dwarf_whatform(&loc) == DW_FORM_sec_offset); | ||
921 | } | ||
922 | |||
923 | /* | ||
924 | * For any object in given CU whose DW_AT_location is a location list, | ||
925 | * target program is compiled with optimization. | ||
926 | */ | ||
927 | static bool optimized_target(Dwarf_Die *cu_die) | ||
928 | { | ||
929 | Dwarf_Die tmp_die; | ||
930 | |||
931 | if (var_has_loclist(cu_die)) | ||
932 | return true; | ||
933 | |||
934 | if (!dwarf_child(cu_die, &tmp_die) && optimized_target(&tmp_die)) | ||
935 | return true; | ||
936 | |||
937 | if (!dwarf_siblingof(cu_die, &tmp_die) && optimized_target(&tmp_die)) | ||
938 | return true; | ||
939 | |||
940 | return false; | ||
941 | } | ||
942 | |||
943 | static bool get_entrypc_idx(Dwarf_Lines *lines, unsigned long nr_lines, | ||
944 | Dwarf_Addr pf_addr, unsigned long *entrypc_idx) | ||
945 | { | ||
946 | unsigned long i; | ||
947 | Dwarf_Addr addr; | ||
948 | |||
949 | for (i = 0; i < nr_lines; i++) { | ||
950 | if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &addr)) | ||
951 | return false; | ||
952 | |||
953 | if (addr == pf_addr) { | ||
954 | *entrypc_idx = i; | ||
955 | return true; | ||
956 | } | ||
957 | } | ||
958 | return false; | ||
959 | } | ||
960 | |||
961 | static bool get_postprologue_addr(unsigned long entrypc_idx, | ||
962 | Dwarf_Lines *lines, | ||
963 | unsigned long nr_lines, | ||
964 | Dwarf_Addr highpc, | ||
965 | Dwarf_Addr *postprologue_addr) | ||
966 | { | ||
967 | unsigned long i; | ||
968 | int entrypc_lno, lno; | ||
969 | Dwarf_Line *line; | ||
970 | Dwarf_Addr addr; | ||
971 | bool p_end; | ||
972 | |||
973 | /* entrypc_lno is actual source line number */ | ||
974 | line = dwarf_onesrcline(lines, entrypc_idx); | ||
975 | if (dwarf_lineno(line, &entrypc_lno)) | ||
976 | return false; | ||
977 | |||
978 | for (i = entrypc_idx; i < nr_lines; i++) { | ||
979 | line = dwarf_onesrcline(lines, i); | ||
980 | |||
981 | if (dwarf_lineaddr(line, &addr) || | ||
982 | dwarf_lineno(line, &lno) || | ||
983 | dwarf_lineprologueend(line, &p_end)) | ||
984 | return false; | ||
985 | |||
986 | /* highpc is exclusive. [entrypc,highpc) */ | ||
987 | if (addr >= highpc) | ||
988 | break; | ||
989 | |||
990 | /* clang supports prologue-end marker */ | ||
991 | if (p_end) | ||
992 | break; | ||
993 | |||
994 | /* Actual next line in source */ | ||
995 | if (lno != entrypc_lno) | ||
996 | break; | ||
997 | |||
998 | /* | ||
999 | * Single source line can have multiple line records. | ||
1000 | * For Example, | ||
1001 | * void foo() { printf("hello\n"); } | ||
1002 | * contains two line records. One points to declaration and | ||
1003 | * other points to printf() line. Variable 'lno' won't get | ||
1004 | * incremented in this case but 'i' will. | ||
1005 | */ | ||
1006 | if (i != entrypc_idx) | ||
1007 | break; | ||
1008 | } | ||
1009 | |||
1010 | dwarf_lineaddr(line, postprologue_addr); | ||
1011 | if (*postprologue_addr >= highpc) | ||
1012 | dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), | ||
1013 | postprologue_addr); | ||
1014 | |||
1015 | return true; | ||
1016 | } | ||
1017 | |||
1018 | static void __skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) | ||
1019 | { | ||
1020 | size_t nr_lines = 0; | ||
1021 | unsigned long entrypc_idx = 0; | ||
1022 | Dwarf_Lines *lines = NULL; | ||
1023 | Dwarf_Addr postprologue_addr; | ||
1024 | Dwarf_Addr highpc; | ||
1025 | |||
1026 | if (dwarf_highpc(sp_die, &highpc)) | ||
1027 | return; | ||
1028 | |||
1029 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nr_lines)) | ||
1030 | return; | ||
1031 | |||
1032 | if (!get_entrypc_idx(lines, nr_lines, pf->addr, &entrypc_idx)) | ||
1033 | return; | ||
1034 | |||
1035 | if (!get_postprologue_addr(entrypc_idx, lines, nr_lines, | ||
1036 | highpc, &postprologue_addr)) | ||
1037 | return; | ||
1038 | |||
1039 | pf->addr = postprologue_addr; | ||
1040 | } | ||
1041 | |||
1042 | static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) | 910 | static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) |
1043 | { | 911 | { |
1044 | struct perf_probe_point *pp = &pf->pev->point; | 912 | struct perf_probe_point *pp = &pf->pev->point; |
@@ -1048,7 +916,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1048 | return; | 916 | return; |
1049 | 917 | ||
1050 | /* Compiled with optimization? */ | 918 | /* Compiled with optimization? */ |
1051 | if (optimized_target(&pf->cu_die)) | 919 | if (die_is_optimized_target(&pf->cu_die)) |
1052 | return; | 920 | return; |
1053 | 921 | ||
1054 | /* Don't know entrypc? */ | 922 | /* Don't know entrypc? */ |
@@ -1068,7 +936,7 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1068 | "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", | 936 | "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n", |
1069 | pf->addr); | 937 | pf->addr); |
1070 | 938 | ||
1071 | __skip_prologue(sp_die, pf); | 939 | die_skip_prologue(sp_die, &pf->cu_die, &pf->addr); |
1072 | } | 940 | } |
1073 | 941 | ||
1074 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 942 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |