diff options
Diffstat (limited to 'tools/perf/util/dwarf-aux.c')
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 207 |
1 files changed, 205 insertions, 2 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index a347b19c961a..41e068e94349 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -130,6 +130,22 @@ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /** | 132 | /** |
133 | * die_get_linkage_name - Get the linkage name of the object | ||
134 | * @dw_die: A DIE of the object | ||
135 | * | ||
136 | * Get the linkage name attiribute of given @dw_die. | ||
137 | * For C++ binary, the linkage name will be the mangled symbol. | ||
138 | */ | ||
139 | const char *die_get_linkage_name(Dwarf_Die *dw_die) | ||
140 | { | ||
141 | Dwarf_Attribute attr; | ||
142 | |||
143 | if (dwarf_attr_integrate(dw_die, DW_AT_linkage_name, &attr) == NULL) | ||
144 | return NULL; | ||
145 | return dwarf_formstring(&attr); | ||
146 | } | ||
147 | |||
148 | /** | ||
133 | * die_compare_name - Compare diename and tname | 149 | * die_compare_name - Compare diename and tname |
134 | * @dw_die: a DIE | 150 | * @dw_die: a DIE |
135 | * @tname: a string of target name | 151 | * @tname: a string of target name |
@@ -145,18 +161,26 @@ bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | |||
145 | } | 161 | } |
146 | 162 | ||
147 | /** | 163 | /** |
148 | * die_match_name - Match diename and glob | 164 | * die_match_name - Match diename/linkage name and glob |
149 | * @dw_die: a DIE | 165 | * @dw_die: a DIE |
150 | * @glob: a string of target glob pattern | 166 | * @glob: a string of target glob pattern |
151 | * | 167 | * |
152 | * Glob matching the name of @dw_die and @glob. Return false if matching fail. | 168 | * Glob matching the name of @dw_die and @glob. Return false if matching fail. |
169 | * This also match linkage name. | ||
153 | */ | 170 | */ |
154 | bool die_match_name(Dwarf_Die *dw_die, const char *glob) | 171 | bool die_match_name(Dwarf_Die *dw_die, const char *glob) |
155 | { | 172 | { |
156 | const char *name; | 173 | const char *name; |
157 | 174 | ||
158 | name = dwarf_diename(dw_die); | 175 | name = dwarf_diename(dw_die); |
159 | return name ? strglobmatch(name, glob) : false; | 176 | if (name && strglobmatch(name, glob)) |
177 | return true; | ||
178 | /* fall back to check linkage name */ | ||
179 | name = die_get_linkage_name(dw_die); | ||
180 | if (name && strglobmatch(name, glob)) | ||
181 | return true; | ||
182 | |||
183 | return false; | ||
160 | } | 184 | } |
161 | 185 | ||
162 | /** | 186 | /** |
@@ -1085,3 +1109,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, | |||
1085 | return -ENOTSUP; | 1109 | return -ENOTSUP; |
1086 | } | 1110 | } |
1087 | #endif | 1111 | #endif |
1112 | |||
1113 | /* | ||
1114 | * die_has_loclist - Check if DW_AT_location of @vr_die is a location list | ||
1115 | * @vr_die: a variable DIE | ||
1116 | */ | ||
1117 | static bool die_has_loclist(Dwarf_Die *vr_die) | ||
1118 | { | ||
1119 | Dwarf_Attribute loc; | ||
1120 | int tag = dwarf_tag(vr_die); | ||
1121 | |||
1122 | if (tag != DW_TAG_formal_parameter && | ||
1123 | tag != DW_TAG_variable) | ||
1124 | return false; | ||
1125 | |||
1126 | return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) && | ||
1127 | dwarf_whatform(&loc) == DW_FORM_sec_offset); | ||
1128 | } | ||
1129 | |||
1130 | /* | ||
1131 | * die_is_optimized_target - Check if target program is compiled with | ||
1132 | * optimization | ||
1133 | * @cu_die: a CU DIE | ||
1134 | * | ||
1135 | * For any object in given CU whose DW_AT_location is a location list, | ||
1136 | * target program is compiled with optimization. This is applicable to | ||
1137 | * clang as well. | ||
1138 | */ | ||
1139 | bool die_is_optimized_target(Dwarf_Die *cu_die) | ||
1140 | { | ||
1141 | Dwarf_Die tmp_die; | ||
1142 | |||
1143 | if (die_has_loclist(cu_die)) | ||
1144 | return true; | ||
1145 | |||
1146 | if (!dwarf_child(cu_die, &tmp_die) && | ||
1147 | die_is_optimized_target(&tmp_die)) | ||
1148 | return true; | ||
1149 | |||
1150 | if (!dwarf_siblingof(cu_die, &tmp_die) && | ||
1151 | die_is_optimized_target(&tmp_die)) | ||
1152 | return true; | ||
1153 | |||
1154 | return false; | ||
1155 | } | ||
1156 | |||
1157 | /* | ||
1158 | * die_search_idx - Search index of given line address | ||
1159 | * @lines: Line records of single CU | ||
1160 | * @nr_lines: Number of @lines | ||
1161 | * @addr: address we are looking for | ||
1162 | * @idx: index to be set by this function (return value) | ||
1163 | * | ||
1164 | * Search for @addr by looping over every lines of CU. If address | ||
1165 | * matches, set index of that line in @idx. Note that single source | ||
1166 | * line can have multiple line records. i.e. single source line can | ||
1167 | * have multiple index. | ||
1168 | */ | ||
1169 | static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines, | ||
1170 | Dwarf_Addr addr, unsigned long *idx) | ||
1171 | { | ||
1172 | unsigned long i; | ||
1173 | Dwarf_Addr tmp; | ||
1174 | |||
1175 | for (i = 0; i < nr_lines; i++) { | ||
1176 | if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp)) | ||
1177 | return false; | ||
1178 | |||
1179 | if (tmp == addr) { | ||
1180 | *idx = i; | ||
1181 | return true; | ||
1182 | } | ||
1183 | } | ||
1184 | return false; | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * die_get_postprologue_addr - Search next address after function prologue | ||
1189 | * @entrypc_idx: entrypc index | ||
1190 | * @lines: Line records of single CU | ||
1191 | * @nr_lines: Number of @lines | ||
1192 | * @hignpc: high PC address of function | ||
1193 | * @postprologue_addr: Next address after function prologue (return value) | ||
1194 | * | ||
1195 | * Look for prologue-end marker. If there is no explicit marker, return | ||
1196 | * address of next line record or next source line. | ||
1197 | */ | ||
1198 | static bool die_get_postprologue_addr(unsigned long entrypc_idx, | ||
1199 | Dwarf_Lines *lines, | ||
1200 | unsigned long nr_lines, | ||
1201 | Dwarf_Addr highpc, | ||
1202 | Dwarf_Addr *postprologue_addr) | ||
1203 | { | ||
1204 | unsigned long i; | ||
1205 | int entrypc_lno, lno; | ||
1206 | Dwarf_Line *line; | ||
1207 | Dwarf_Addr addr; | ||
1208 | bool p_end; | ||
1209 | |||
1210 | /* entrypc_lno is actual source line number */ | ||
1211 | line = dwarf_onesrcline(lines, entrypc_idx); | ||
1212 | if (dwarf_lineno(line, &entrypc_lno)) | ||
1213 | return false; | ||
1214 | |||
1215 | for (i = entrypc_idx; i < nr_lines; i++) { | ||
1216 | line = dwarf_onesrcline(lines, i); | ||
1217 | |||
1218 | if (dwarf_lineaddr(line, &addr) || | ||
1219 | dwarf_lineno(line, &lno) || | ||
1220 | dwarf_lineprologueend(line, &p_end)) | ||
1221 | return false; | ||
1222 | |||
1223 | /* highpc is exclusive. [entrypc,highpc) */ | ||
1224 | if (addr >= highpc) | ||
1225 | break; | ||
1226 | |||
1227 | /* clang supports prologue-end marker */ | ||
1228 | if (p_end) | ||
1229 | break; | ||
1230 | |||
1231 | /* Actual next line in source */ | ||
1232 | if (lno != entrypc_lno) | ||
1233 | break; | ||
1234 | |||
1235 | /* | ||
1236 | * Single source line can have multiple line records. | ||
1237 | * For Example, | ||
1238 | * void foo() { printf("hello\n"); } | ||
1239 | * contains two line records. One points to declaration and | ||
1240 | * other points to printf() line. Variable 'lno' won't get | ||
1241 | * incremented in this case but 'i' will. | ||
1242 | */ | ||
1243 | if (i != entrypc_idx) | ||
1244 | break; | ||
1245 | } | ||
1246 | |||
1247 | dwarf_lineaddr(line, postprologue_addr); | ||
1248 | if (*postprologue_addr >= highpc) | ||
1249 | dwarf_lineaddr(dwarf_onesrcline(lines, i - 1), | ||
1250 | postprologue_addr); | ||
1251 | |||
1252 | return true; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * die_skip_prologue - Use next address after prologue as probe location | ||
1257 | * @sp_die: a subprogram DIE | ||
1258 | * @cu_die: a CU DIE | ||
1259 | * @entrypc: entrypc of the function | ||
1260 | * | ||
1261 | * Function prologue prepares stack and registers before executing function | ||
1262 | * logic. When target program is compiled without optimization, function | ||
1263 | * parameter information is only valid after prologue. When we probe entrypc | ||
1264 | * of the function, and try to record function parameter, it contains | ||
1265 | * garbage value. | ||
1266 | */ | ||
1267 | void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, | ||
1268 | Dwarf_Addr *entrypc) | ||
1269 | { | ||
1270 | size_t nr_lines = 0; | ||
1271 | unsigned long entrypc_idx = 0; | ||
1272 | Dwarf_Lines *lines = NULL; | ||
1273 | Dwarf_Addr postprologue_addr; | ||
1274 | Dwarf_Addr highpc; | ||
1275 | |||
1276 | if (dwarf_highpc(sp_die, &highpc)) | ||
1277 | return; | ||
1278 | |||
1279 | if (dwarf_getsrclines(cu_die, &lines, &nr_lines)) | ||
1280 | return; | ||
1281 | |||
1282 | if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx)) | ||
1283 | return; | ||
1284 | |||
1285 | if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines, | ||
1286 | highpc, &postprologue_addr)) | ||
1287 | return; | ||
1288 | |||
1289 | *entrypc = postprologue_addr; | ||
1290 | } | ||