skel->bss->needs_callstack = con->save_callstack;
        skel->bss->lock_owner = con->owner;
 
+       bpf_program__set_autoload(skel->progs.collect_lock_syms, false);
+
        lock_contention_bpf__attach(skel);
        return 0;
 }
        }
 
        if (con->aggr_mode == LOCK_AGGR_ADDR) {
+               int lock_fd = bpf_map__fd(skel->maps.lock_syms);
+
+               /* per-process locks set upper bits of the flags */
                if (flags & LCD_F_MMAP_LOCK)
                        return "mmap_lock";
                if (flags & LCD_F_SIGHAND_LOCK)
                        return "siglock";
+
+               /* global locks with symbols */
                sym = machine__find_kernel_symbol(machine, key->lock_addr, &kmap);
                if (sym)
-                       name = sym->name;
-               return name;
+                       return sym->name;
+
+               /* try semi-global locks collected separately */
+               if (!bpf_map_lookup_elem(lock_fd, &key->lock_addr, &flags)) {
+                       if (flags == LOCK_CLASS_RQLOCK)
+                               return "rq_lock";
+               }
+
+               return "";
        }
 
        /* LOCK_AGGR_CALLER: skip lock internal functions */
                thread__set_comm(idle, "swapper", /*timestamp=*/0);
        }
 
+       if (con->aggr_mode == LOCK_AGGR_ADDR) {
+               DECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,
+                       .flags = BPF_F_TEST_RUN_ON_CPU,
+               );
+               int prog_fd = bpf_program__fd(skel->progs.collect_lock_syms);
+
+               bpf_prog_test_run_opts(prog_fd, &opts);
+       }
+
        /* make sure it loads the kernel map */
        map__load(maps__first(machine->kmaps));
 
 
 /* default buffer size */
 #define MAX_ENTRIES  10240
 
+/* for collect_lock_syms().  4096 was rejected by the verifier */
+#define MAX_CPUS  1024
+
 /* lock contention flags from include/trace/events/lock.h */
 #define LCB_F_SPIN     (1U << 0)
 #define LCB_F_READ     (1U << 1)
        __uint(max_entries, MAX_ENTRIES);
 } task_data SEC(".maps");
 
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __uint(key_size, sizeof(__u64));
+       __uint(value_size, sizeof(__u32));
+       __uint(max_entries, 16384);
+} lock_syms SEC(".maps");
+
 struct {
        __uint(type, BPF_MAP_TYPE_HASH);
        __uint(key_size, sizeof(__u32));
        return 0;
 }
 
+extern struct rq runqueues __ksym;
+
+SEC("raw_tp/bpf_test_finish")
+int BPF_PROG(collect_lock_syms)
+{
+       __u64 lock_addr;
+       __u32 lock_flag;
+
+       for (int i = 0; i < MAX_CPUS; i++) {
+               struct rq *rq = bpf_per_cpu_ptr(&runqueues, i);
+
+               if (rq == NULL)
+                       break;
+
+               lock_addr = (__u64)&rq->__lock;
+               lock_flag = LOCK_CLASS_RQLOCK;
+               bpf_map_update_elem(&lock_syms, &lock_addr, &lock_flag, BPF_ANY);
+       }
+       return 0;
+}
+
 char LICENSE[] SEC("license") = "Dual BSD/GPL";