|
3 | 3 | * Copyright (C) 2024 Google LLC |
4 | 4 | */ |
5 | 5 |
|
| 6 | +#define _GNU_SOURCE |
6 | 7 | #include <assert.h> |
7 | 8 | #include <inttypes.h> |
8 | 9 | #include <stdarg.h> |
@@ -193,79 +194,17 @@ static void process_fmt(struct die *cache, const char *fmt, ...) |
193 | 194 | va_end(args); |
194 | 195 | } |
195 | 196 |
|
196 | | -#define MAX_FQN_SIZE 64 |
197 | | - |
198 | | -/* Get a fully qualified name from DWARF scopes */ |
199 | | -static char *get_fqn(Dwarf_Die *die) |
| 197 | +static void update_fqn(struct die *cache, Dwarf_Die *die) |
200 | 198 | { |
201 | | - const char *list[MAX_FQN_SIZE]; |
202 | | - Dwarf_Die *scopes = NULL; |
203 | | - bool has_name = false; |
204 | | - char *fqn = NULL; |
205 | | - char *p; |
206 | | - int count = 0; |
207 | | - int len = 0; |
208 | | - int res; |
209 | | - int i; |
210 | | - |
211 | | - res = checkp(dwarf_getscopes_die(die, &scopes)); |
212 | | - if (!res) { |
213 | | - list[count] = get_name_attr(die); |
214 | | - |
215 | | - if (!list[count]) |
216 | | - return NULL; |
217 | | - |
218 | | - len += strlen(list[count]); |
219 | | - count++; |
220 | | - |
221 | | - goto done; |
222 | | - } |
223 | | - |
224 | | - for (i = res - 1; i >= 0 && count < MAX_FQN_SIZE; i--) { |
225 | | - if (dwarf_tag(&scopes[i]) == DW_TAG_compile_unit) |
226 | | - continue; |
227 | | - |
228 | | - list[count] = get_name_attr(&scopes[i]); |
229 | | - |
230 | | - if (list[count]) { |
231 | | - has_name = true; |
232 | | - } else { |
233 | | - list[count] = "<anonymous>"; |
234 | | - has_name = false; |
235 | | - } |
| 199 | + struct die *fqn; |
236 | 200 |
|
237 | | - len += strlen(list[count]); |
238 | | - count++; |
239 | | - |
240 | | - if (i > 0) { |
241 | | - list[count++] = "::"; |
242 | | - len += 2; |
243 | | - } |
| 201 | + if (!cache->fqn) { |
| 202 | + if (!__die_map_get((uintptr_t)die->addr, DIE_FQN, &fqn) && |
| 203 | + *fqn->fqn) |
| 204 | + cache->fqn = xstrdup(fqn->fqn); |
| 205 | + else |
| 206 | + cache->fqn = ""; |
244 | 207 | } |
245 | | - |
246 | | - free(scopes); |
247 | | - |
248 | | - if (count == MAX_FQN_SIZE) |
249 | | - warn("increase MAX_FQN_SIZE: reached the maximum"); |
250 | | - |
251 | | - /* Consider the DIE unnamed if the last scope doesn't have a name */ |
252 | | - if (!has_name) |
253 | | - return NULL; |
254 | | -done: |
255 | | - fqn = xmalloc(len + 1); |
256 | | - *fqn = '\0'; |
257 | | - |
258 | | - p = fqn; |
259 | | - for (i = 0; i < count; i++) |
260 | | - p = stpcpy(p, list[i]); |
261 | | - |
262 | | - return fqn; |
263 | | -} |
264 | | - |
265 | | -static void update_fqn(struct die *cache, Dwarf_Die *die) |
266 | | -{ |
267 | | - if (!cache->fqn) |
268 | | - cache->fqn = get_fqn(die) ?: ""; |
269 | 208 | } |
270 | 209 |
|
271 | 210 | static void process_fqn(struct die *cache, Dwarf_Die *die) |
@@ -1148,8 +1087,81 @@ static void process_symbol_ptr(struct symbol *sym, void *arg) |
1148 | 1087 | cache_free(&state.expansion_cache); |
1149 | 1088 | } |
1150 | 1089 |
|
| 1090 | +static int resolve_fqns(struct state *parent, struct die *unused, |
| 1091 | + Dwarf_Die *die) |
| 1092 | +{ |
| 1093 | + struct state state; |
| 1094 | + struct die *cache; |
| 1095 | + const char *name; |
| 1096 | + bool use_prefix; |
| 1097 | + char *prefix = NULL; |
| 1098 | + char *fqn = ""; |
| 1099 | + int tag; |
| 1100 | + |
| 1101 | + if (!__die_map_get((uintptr_t)die->addr, DIE_FQN, &cache)) |
| 1102 | + return 0; |
| 1103 | + |
| 1104 | + tag = dwarf_tag(die); |
| 1105 | + |
| 1106 | + /* |
| 1107 | + * Only namespaces and structures need to pass a prefix to the next |
| 1108 | + * scope. |
| 1109 | + */ |
| 1110 | + use_prefix = tag == DW_TAG_namespace || tag == DW_TAG_class_type || |
| 1111 | + tag == DW_TAG_structure_type; |
| 1112 | + |
| 1113 | + state.expand.current_fqn = NULL; |
| 1114 | + name = get_name_attr(die); |
| 1115 | + |
| 1116 | + if (parent && parent->expand.current_fqn && (use_prefix || name)) { |
| 1117 | + /* |
| 1118 | + * The fqn for the current DIE, and if needed, a prefix for the |
| 1119 | + * next scope. |
| 1120 | + */ |
| 1121 | + if (asprintf(&prefix, "%s::%s", parent->expand.current_fqn, |
| 1122 | + name ? name : "<anonymous>") < 0) |
| 1123 | + error("asprintf failed"); |
| 1124 | + |
| 1125 | + if (use_prefix) |
| 1126 | + state.expand.current_fqn = prefix; |
| 1127 | + |
| 1128 | + /* |
| 1129 | + * Use fqn only if the DIE has a name. Otherwise fqn will |
| 1130 | + * remain empty. |
| 1131 | + */ |
| 1132 | + if (name) { |
| 1133 | + fqn = prefix; |
| 1134 | + /* prefix will be freed by die_map. */ |
| 1135 | + prefix = NULL; |
| 1136 | + } |
| 1137 | + } else if (name) { |
| 1138 | + /* No prefix from the previous scope. Use only the name. */ |
| 1139 | + fqn = xstrdup(name); |
| 1140 | + |
| 1141 | + if (use_prefix) |
| 1142 | + state.expand.current_fqn = fqn; |
| 1143 | + } |
| 1144 | + |
| 1145 | + /* If the DIE has a non-empty name, cache it. */ |
| 1146 | + if (*fqn) { |
| 1147 | + cache = die_map_get(die, DIE_FQN); |
| 1148 | + /* Move ownership of fqn to die_map. */ |
| 1149 | + cache->fqn = fqn; |
| 1150 | + cache->state = DIE_FQN; |
| 1151 | + } |
| 1152 | + |
| 1153 | + check(process_die_container(&state, NULL, die, resolve_fqns, |
| 1154 | + match_all)); |
| 1155 | + |
| 1156 | + free(prefix); |
| 1157 | + return 0; |
| 1158 | +} |
| 1159 | + |
1151 | 1160 | void process_cu(Dwarf_Die *cudie) |
1152 | 1161 | { |
| 1162 | + check(process_die_container(NULL, NULL, cudie, resolve_fqns, |
| 1163 | + match_all)); |
| 1164 | + |
1153 | 1165 | check(process_die_container(NULL, NULL, cudie, process_exported_symbols, |
1154 | 1166 | match_all)); |
1155 | 1167 |
|
|
0 commit comments