# gdb script: name the first failing call inside FUN_003e90c0 (ucode-image # create, second half) after FUN_003d1e70 (blob parse) succeeded. # # PART 76 chain: FUN_00e21850 -> FUN_003e99d0 -> FUN_003d1e70 OK -> # FUN_003e90c0 returns 1. This script breaks after EVERY call in # FUN_003e90c0 (file 0x2e90c0..0x2e99b5), prints the return value, and # finally prints the function's return + the caller's test site # (CREATE2_RET at 0x2e9a3f). # # Run: sudo gdb -p -batch -x /tmp/bpz10.py import gdb import time out = gdb.execute("info proc mappings", to_string=True) base = None for line in out.splitlines(): if "libcuda" in line and "r-xp" in line: f = line.split() base = int(f[0], 16) - int(f[3], 16) break print("BASE=0x%x" % (base or 0)) if base is None: raise SystemExit gdb.execute("set pagination off") gdb.execute("set confirm off") # (file offset of the instruction AFTER the call, short name) SITES = [ (0x2e9110, "calloc"), (0x2e912a, "FUN_004aa820_alloc"), (0x2e918e, "FUN_00390290_status"), (0x2e91b3, "FUN_003df0d0_status"), (0x2e91f1, "destr_2e84d0"), (0x2e921d, "FUN_00391ee0_status"), (0x2e923c, "FUN_00371fa0_status"), (0x2e9282, "mutex_lock84"), (0x2e92b7, "mutex_unlock84"), (0x2e92bf, "FUN_00e4f3e0_status"), (0x2e9304, "mutex_lock68"), (0x2e931a, "mutex_unlock68"), (0x2e932a, "FUN_00363430_bool"), (0x2e9336, "FUN_003df340_bool"), (0x2e9363, "FUN_00406ff0_status"), (0x2e93ba, "FUN_00394190_status"), (0x2e93c9, "FUN_003bf520_status"), (0x2e9449, "free_a"), (0x2e9478, "FUN_00400550"), (0x2e948e, "FUN_004ab390"), (0x2e9497, "free_b"), (0x2e94a8, "free_c"), (0x2e94b6, "free_d_fail"), (0x2e9505, "FUN_003011e0_status"), (0x2e9525, "ind_0xa0_status"), (0x2e9564, "unlock_fail"), (0x2e9598, "unlock_b"), (0x2e95fc, "FUN_00e4b8c0"), (0x2e9615, "ind_0x4a48_ptr"), (0x2e9628, "FUN_005a5530"), (0x2e9643, "FUN_003df340_bool2"), (0x2e967a, "FUN_00e4f200_status"), (0x2e9687, "FUN_0034a4d0_bool"), (0x2e96e4, "FUN_00251730_done"), (0x2e9717, "unlock_ret0"), (0x2e9788, "FUN_003bf520_status2"), (0x2e97fa, "fprintf_fail"), (0x2e9808, "FUN_003be020_bool"), (0x2e9824, "FUN_0036b900_bool"), (0x2e9857, "FUN_003df340_bool3"), (0x2e9936, "FUN_00e4f2d0"), (0x2e9203, "FUN_3e90c0_RET"), (0x2e9a23, "PARSE_RET"), (0x2e9a3f, "CREATE2_RET"), ] NAMES = dict(SITES) for off, name in SITES: gdb.execute("break *0x%x" % (base + off)) t0 = time.time() hits = 0 last_nonzero = None inv = 0 while hits < 500: try: gdb.execute("continue") except gdb.error as e: print("CONTINUE_END %s" % e) break hits += 1 rip = int(gdb.parse_and_eval("$rip")) & 0xffffffffffffffff off = rip - base name = NAMES.get(off, "?") eax = int(gdb.parse_and_eval("$eax")) & 0xffffffff r15 = int(gdb.parse_and_eval("$r15d")) & 0xffffffff print("HIT %d t=%.3f off=0x%x %-24s eax=0x%x r15=0x%x" % (hits, time.time() - t0, off, name, eax, r15)) if name in ("FUN_00390290_status", "FUN_003df0d0_status", "FUN_00391ee0_status", "FUN_00371fa0_status", "FUN_00e4f3e0_status", "FUN_00406ff0_status", "FUN_00394190_status", "FUN_003bf520_status", "FUN_003bf520_status2", "FUN_003011e0_status", "FUN_00e4f200_status") and eax != 0: last_nonzero = (name, eax) print(" >>> LAST NONZERO %s = 0x%x" % (name, eax)) if name == "FUN_3e90c0_RET": inv += 1 print("INV %d FUN_3e90c0 return r15/eax=0x%x" % (inv, r15)) if last_nonzero: print(" last nonzero status call: %s = 0x%x" % last_nonzero) if r15 != 0: try: print(gdb.execute("bt 6", to_string=True)) except Exception as e: print("bt_fail %s" % e) break last_nonzero = None if name == "CREATE2_RET": print("CREATE2_RET eax=0x%x" % eax) if eax != 0: break try: gdb.execute("detach") except Exception: pass