*             yet used)
  *     -1 in case of errors
  */
-static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
+static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
 {
        int             rc = -1;
        Dwfl            *dwfl;
        Dwarf_Addr      end = pc;
        bool            signalp;
 
-       dwfl = dwfl_begin(&offline_callbacks);
-       if (!dwfl) {
-               pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
-               return -1;
-       }
+       dwfl = dso->dwfl;
 
-       if (dwfl_report_offline(dwfl, "",  exec_file, -1) == NULL) {
-               pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1));
-               goto out;
+       if (!dwfl) {
+               dwfl = dwfl_begin(&offline_callbacks);
+               if (!dwfl) {
+                       pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
+                       return -1;
+               }
+
+               if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) {
+                       pr_debug("dwfl_report_offline() failed %s\n",
+                                               dwarf_errmsg(-1));
+                       /*
+                        * We normally cache the DWARF debug info and never
+                        * call dwfl_end(). But to prevent fd leak, free in
+                        * case of error.
+                        */
+                       dwfl_end(dwfl);
+                       goto out;
+               }
+               dso->dwfl = dwfl;
        }
 
        mod = dwfl_addrmodule(dwfl, pc);
        rc = check_return_reg(ra_regno, frame);
 
 out:
-       dwfl_end(dwfl);
        return rc;
 }
 
                return skip_slot;
        }
 
-       rc = check_return_addr(dso->long_name, ip);
+       rc = check_return_addr(dso, ip);
 
        pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
                                dso->long_name, chain->nr, ip, rc);