Commits

Anonymous committed 843d1cb

resolve an issue on 32-bit systems.

We treat pointers as 64-bit througout the code but had some places
that assumed 32-bit. This lead to a crash in printf on a 32-bit linux
system.

Resolved this by making sure we're not mixing void* with gimli_addr_t
and adding appropriate accessors.

Also discovered that using pread/pwrite is dangerous on a 32-bit system
in general, as the top of stack ends up being represented by a negative
off_t offset, and leads to failure to correctly interrogate the target
process.

Moving to pread64 and pwrite64 resolves this issue.

This patch is mostly cast removal or fixing.
I have compiled and run this test:

{{{
LD_LIBRARY_PATH=.libs ./monitor --debug=1 --detach=0 \
--glider=.libs/glider --run-once=1 ./wedgie
}}}

on a 64-bit Linux system, building with `CC="gcc -m32"` to verify the
32-bit compilation, and a 64-Solaris system doing the same.

refs #11187 (spent 4)

Comments (0)

Files changed (14)

 {
   uint64_t l;
   int ret = gimli_determine_source_line_number(the_proc,
-      (gimli_addr_t)addr, buf, buflen, &l);
+      (gimli_addr_t)(intptr_t)addr, buf, buflen, &l);
   if (ret) {
     *lineno = (int)l;
   }
 static const char *v1_pc_sym_name(void *addr,
     char *buf, int buflen)
 {
-  return gimli_pc_sym_name(the_proc, (gimli_addr_t)addr, buf, buflen);
+  return gimli_pc_sym_name(the_proc, (gimli_addr_t)(intptr_t)addr, buf, buflen);
 }
 
 static int v1_read_mem(void *src, void *dest, int len)
 {
-  return gimli_read_mem(the_proc, (gimli_addr_t)src, dest, len);
+  return gimli_read_mem(the_proc, (gimli_addr_t)(intptr_t)src, dest, len);
 }
 
 static char *v1_read_string(void *src)
 {
-  return gimli_read_string(the_proc, (gimli_addr_t)src);
+  return gimli_read_string(the_proc, (gimli_addr_t)(intptr_t)src);
 }
 
 static int v2_get_parameter(void *context, const char *varname,
     return 0;
   }
 
-  *addrp = (void*)addr;
+  *addrp = (void*)(intptr_t)addr;
   *sizep = gimli_type_size(t);
   *datatypep = gimli_type_declname(t);
 
   return 1;
 }
 
-static int get_reg(struct gimli_unwind_cursor *cur, int regno, uint64_t *val)
-{
-  void **addr = gimli_reg_addr(cur, regno);
-  if (!addr) {
-    fprintf(stderr, "DWARF: expr: no address for reg %d\n", regno);
-    return 0;
-  }
-  *val = (uint64_t)(intptr_t)*addr;
-  return 1;
-}
-
 int dw_eval_expr(struct gimli_unwind_cursor *cur, const uint8_t *ops,
   uint64_t oplen,
   uint64_t frame_base, uint64_t *result, uint64_t *prepopulate,
       s64 = dw_read_leb128(&e.ops, e.end);
       val.is_signed = 0;
       val.is_stack = 1;
-      if (!get_reg(cur, op - DW_OP_breg0, &val.v.u64)) return 0;
+      if (!gimli_reg_get(cur, op - DW_OP_breg0, &val.v.u64)) return 0;
       if (debug) printf("OP_breg%d val=%" PRIx64 "\n", op - DW_OP_breg0, val.v.u64);
       val.v.u64 += s64;
       if (!push(&e, &val)) return 0;
     if (op >= DW_OP_reg0 && op <= DW_OP_reg31) {
       val.is_signed = 0;
       val.is_stack = 0;
-      if (!get_reg(cur, op - DW_OP_reg0, &val.v.u64)) return 0;
+      if (!gimli_reg_get(cur, op - DW_OP_reg0, &val.v.u64)) return 0;
       if (debug) printf("OP_reg%d -> %" PRIx64 "\n", op - DW_OP_reg0, val.v.u64);
       if (!push(&e, &val)) return 0;
       continue;
         s64 = dw_read_leb128(&e.ops, e.end);
         val.is_signed = 0;
         val.is_stack = 1;
-        if (!get_reg(cur, u64, &val.v.u64)) return 0;
+        if (!gimli_reg_get(cur, u64, &val.v.u64)) return 0;
         val.v.u64 += s64;
         if (debug) printf("OP_breg%" PRId64 ": %" PRIx64 "\n", u64, val.v.u64);
         if (!push(&e, &val)) return 0;
         u64 = dw_read_uleb128(&e.ops, e.end);
         val.is_signed = 0;
         val.is_stack = 0;
-        if (!get_reg(cur, u64, &val.v.u64)) return 0;
+        if (!gimli_reg_get(cur, u64, &val.v.u64)) return 0;
         if (debug) printf("OP_reg%" PRId64 "\n", u64);
         if (!push(&e, &val)) return 0;
         continue;
       break;
     case DW_EH_PE_datarel:
     default:
-      fprintf(stderr, "DWARF: unhandled pointer application value: %02x at %p\n", enc & DW_EH_PE_APPL_MASK, (void*)pc);
+      fprintf(stderr, "DWARF: unhandled pointer application value: %02x at " PTRFMT "\n", enc & DW_EH_PE_APPL_MASK, pc);
       return 0;
   }
 
       }
       break;
     default:
-      fprintf(stderr, "DWARF: unhandled DW_EH_PE value: 0x%02x (masked to 0x%02x) at %p\n", enc, enc & 0x0f, (void*)pc);
+      fprintf(stderr, "DWARF: unhandled DW_EH_PE value: 0x%02x (masked to 0x%02x) at " PTRFMT "\n", enc, enc & 0x0f, pc);
       return 0;
   }
 
 {
   struct gimli_section_data *s = NULL;
   struct {
-    char *address;
+    gimli_addr_t address;
     uint64_t file;
     uint64_t line;
     uint64_t column;
 
   while (data < end) {
     const uint8_t *cuend;
-    void *prior;
+    gimli_addr_t prior;
 
     memset(&regs, 0, sizeof(regs));
     regs.file = 1;
     regs.line = 1;
-    prior = NULL;
+    prior = 0;
 
     /* read the initial length, this tells us which dwarf version and format
      * we're dealing with */
               void *addr;
               memcpy(&addr, data, sizeof(addr));
               if (debugline) fprintf(stderr, "set_address %p\n", addr);
-              regs.address = addr;
+              regs.address = (intptr_t)addr;
               break;
             }
           case DW_LNE_end_sequence:
               uint64_t u = dw_read_uleb128(&data, cuend);
               regs.address += u * hdr_1.min_insn_len;
               if (debugline) {
-                fprintf(stderr, "advance_pc: addr=0x%" PRIx64 "\n", (uintptr_t)regs.address);
+                fprintf(stderr, "advance_pc: addr=" PTRFMT "\n", regs.address);
               }
               break;
             }
             regs.address += ((255 - hdr_1.opcode_base) /
                             hdr_1.line_range) * hdr_1.min_insn_len;
             if (debugline) {
-              fprintf(stderr, "const_add_pc: addr=0x%" PRIx64 "\n", (uintptr_t)regs.address);
+              fprintf(stderr, "const_add_pc: addr=" PTRFMT "\n", regs.address);
             }
             break;
           case DW_LNS_fixed_advance_pc:
             data += sizeof(u);
             regs.address += u;
             if (debugline) {
-              fprintf(stderr, "fixed_advance_pc: 0x%" PRIx64 "\n", (uintptr_t)regs.address);
+              fprintf(stderr, "fixed_advance_pc: " PTRFMT "\n", regs.address);
             }
             break;
           }
         op -= hdr_1.opcode_base;
 
         if (debugline) {
-          fprintf(stderr, "special before: addr = %p, line = %" PRId64 "\n",
+          fprintf(stderr, "special before: addr = " PTRFMT ", line = %" PRId64 "\n",
               regs.address, regs.line);
           fprintf(stderr, "line_base = %d, line_range = %d\n",
             hdr_1.line_base, hdr_1.line_range);
         regs.address += (op / hdr_1.line_range) * hdr_1.min_insn_len;
         regs.line += hdr_1.line_base + (op % hdr_1.line_range);
         if (debugline) {
-          fprintf(stderr, "special: addr = %p, line = %" PRId64 "\n",
+          fprintf(stderr, "special: addr = " PTRFMT ", line = %" PRId64 "\n",
             regs.address, regs.line);
         }
       }
 //    printf("This section is %d bytes in length\n", len);
 
 //    printf("%p - %p\n", rstart, rend);
-    if (cur->st.pc >= rstart && cur->st.pc < rend) {
+    if (cur->st.pc >= (intptr_t)rstart && cur->st.pc < (intptr_t)rend) {
 //      printf("Found the range I was looking for, data=%p, len=%d\n", data, len);
 
       return dw_eval_expr(cur, (uint8_t*)data, len, 0, res, NULL, is_stack);
 
   if (debug) {
     fprintf(stderr,
-      "\nprocess insns: %p to %p, pc = %p\n", insns, insn_end, cur->st.pc);
+      "\nprocess insns: %p to %p, pc = " PTRFMT "\n", insns, insn_end, cur->st.pc);
   }
 
   while (pc <= (intptr_t)cur->st.pc && insns < insn_end) {
   struct dw_cie *cie)
 {
   int i;
-  void *pc = cur->st.pc;
-  void *fp = cur->st.fp;
-  void *regaddr;
-  void *val;
+  gimli_addr_t pc = cur->st.pc;
+  gimli_addr_t fp = cur->st.fp;
+  gimli_addr_t addrval;
+  gimli_addr_t val;
 
   if (debug) {
-    fprintf(stderr, "\napply_regs:\npc=%p fp=%p sp=%p\n",
+    fprintf(stderr, "\napply_regs:\npc=" PTRFMT " fp=" PTRFMT
+        " sp=" PTRFMT "\n",
       cur->st.pc, cur->st.fp, cur->st.sp);
   }
 
     if (debug) {
       fprintf(stderr, "CFA is stored relative to register %d\n", i);
     }
-    regaddr = gimli_reg_addr(cur, i);
-    if (!regaddr) {
-      fprintf(stderr, "DWARF: no address for reg %d\n", i);
+    if (!gimli_reg_get(cur, i, &addrval)) {
       return 0;
     }
-    regaddr = *(void**)regaddr;
     if (debug) {
-      fprintf(stderr, "target addr: %p + %" PRIu64 "\n",
-        regaddr, cur->dw.cols[GIMLI_DWARF_CFA_OFF].value);
+      fprintf(stderr, "target addr: " PTRFMT " + %" PRIu64 "\n",
+        addrval, cur->dw.cols[GIMLI_DWARF_CFA_OFF].value);
     }
-    regaddr += cur->dw.cols[GIMLI_DWARF_CFA_OFF].value;
-    fp = regaddr;
+    addrval += cur->dw.cols[GIMLI_DWARF_CFA_OFF].value;
+    fp = addrval;
     if (debug) {
-      fprintf(stderr, "fp=%p\n", fp);
+      fprintf(stderr, "fp=" PTRFMT "\n", fp);
     }
   } else if (cur->dw.cols[GIMLI_DWARF_CFA_REG].rule == DW_RULE_EXPR) {
     uint64_t ret;
       fprintf(stderr, "failed to evaluate DWARF expression\n");
       return 0;
     }
-    fp = (void*)(intptr_t)ret;
+    fp = ret;
   } else {
     fprintf(stderr, "DWARF: line %d: Unhandled rule %d for CFA\n",
       __LINE__, cur->dw.cols[GIMLI_DWARF_CFA_REG].rule);
     return 0;
   }
   if (debug) {
-    fprintf(stderr, "New CFA is %p\n", fp);
+    fprintf(stderr, "New CFA is " PTRFMT "\n", fp);
   }
 
   for (i = 0; i < GIMLI_DWARF_CFA_REG; i++) {
         /* retains same value */
         break;
       case DW_RULE_OFFSET:
-        regaddr = fp + cur->dw.cols[i].value;
+        addrval = fp + cur->dw.cols[i].value;
         if (debug) {
-          fprintf(stderr, "col %d: CFA relative, reading %p + %" PRIu64 " = %p\n", i,
-            fp, cur->dw.cols[i].value, regaddr);
+          fprintf(stderr, "col %d: CFA relative, reading " PTRFMT " + %" PRIu64 " = " PTRFMT "\n", i,
+            fp, cur->dw.cols[i].value, addrval);
         }
-        if (gimli_read_mem(cur->proc, (gimli_addr_t)regaddr,
+        if (gimli_read_mem(cur->proc, addrval,
               &val, sizeof(val)) != sizeof(val)) {
-          fprintf(stderr, "col %d: couldn't read value\n", i);
+          fprintf(stderr, "col %d: couldn't read value from " PTRFMT "\n", i, addrval);
           return 0;
         }
-        regaddr = gimli_reg_addr(cur, i);
-        if (!regaddr) {
-          printf("couldn't find address for column %d\n", i);
+        if (debug) {
+          fprintf(stderr, "Setting col %d to " PTRFMT "\n", i, val);
+        }
+        gimli_reg_set(cur, i, val);
+        break;
+      case DW_RULE_REG:
+        if (!gimli_reg_get(cur, cur->dw.cols[i].value, &val)) {
           return 0;
         }
-        *(void**)regaddr = val;
         if (debug) {
-          fprintf(stderr, "Setting col %d to %p\n", i, val);
+          fprintf(stderr, "Setting col %d to " PTRFMT "\n", i, val);
         }
-        break;
-      case DW_RULE_REG:
-        regaddr = gimli_reg_addr(cur, cur->dw.cols[i].value);
-        if (!regaddr) {
-          printf("Couldn't find address for register %" PRIu64 "\n",
-            cur->dw.cols[i].value);
-          return 0;
-        }
-        val = *(void**)regaddr;
-        regaddr = gimli_reg_addr(cur, i);
-        if (!regaddr) {
-          printf("couldn't find address for column %d\n", i);
-          return 0;
-        }
-        *(void**)regaddr = val;
-        if (debug) {
-          fprintf(stderr, "Setting col %d to %p\n", i, val);
-        }
+        gimli_reg_set(cur, i, val);
         break;
       case DW_RULE_EXPR:
         {
           uint64_t ret;
-          if (!eval_expr(i, (uint64_t)(intptr_t)fp, &ret, cur)) {
+          if (!eval_expr(i, fp, &ret, cur)) {
             fprintf(stderr, "failed to evaluate DWARF expression\n");
             return 0;
           }
-          regaddr = gimli_reg_addr(cur, i);
-          if (!regaddr) {
-            printf("couldn't find address for column %d\n", i);
-            return 0;
+          if (debug) {
+            fprintf(stderr, "Setting col %d to " PTRFMT "\n", i, ret);
           }
-          val = (void*)(intptr_t)ret;
-          *(void**)regaddr = val;
-          if (debug) {
-            fprintf(stderr, "Setting col %d to %p\n", i, val);
-          }
+          gimli_reg_set(cur, i, ret);
           break;
         }
 
       case DW_RULE_VAL_EXPR:
         {
           uint64_t ret;
-          if (!eval_expr(i, (uint64_t)(intptr_t)fp, &ret, cur)) {
+          if (!eval_expr(i, fp, &ret, cur)) {
             fprintf(stderr, "failed to evaluate DWARF expression\n");
             return 0;
           }
-          regaddr = gimli_reg_addr(cur, i);
-          if (!regaddr) {
-            printf("couldn't find address for column %d\n", i);
-            return 0;
+          if (debug) {
+            fprintf(stderr, "Setting col %d to " PTRFMT "\n", i, ret);
           }
-          *(void**)regaddr = (void*)(intptr_t)ret;
-          if (debug) {
-            fprintf(stderr, "Setting col %d to 0x%" PRIx64 "\n", i, ret);
-          }
+          gimli_reg_set(cur, i, ret);
           break;
         }
 
     fprintf(stderr, "retaddr is in col %" PRIu64 "\n", cie->ret_addr);
   }
 
-  regaddr = gimli_reg_addr(cur, cie->ret_addr);
-  if (!regaddr) {
-    fprintf(stderr, "DWARF: line %d: could not find address for return addr column %" PRIu64 "\n",
-      __LINE__, cie->ret_addr);
+  if (!gimli_reg_get(cur, cie->ret_addr, &pc)) {
     return 0;
   }
-  pc = *(void**)regaddr;
   if (debug) {
-    fprintf(stderr, "new pc is %p\n", pc);
+    fprintf(stderr, "new pc is " PTRFMT "\n", pc);
   }
   cur->st.pc = pc;
   cur->st.fp = fp;
                   s->addr + eh_frame - eh_start,
                   &cie->personality_routine)) {
               fprintf(stderr, "Error reading personality routine, "
-                  "enc=%02x offset: %lx\n", enc, eh_frame - eh_start);
+                  "enc=%02x offset: %" PRIx32 "\n", enc,
+                  (uint32_t)(eh_frame - eh_start));
               return 0;
             }
           } else if (*aug == 'R') {
 
 static int search_compare_fde(const void *PC, const void *FDE)
 {
-  intptr_t pc = (intptr_t)*(void**)PC;
+  gimli_addr_t pc = *(gimli_addr_t*)PC;
   struct dw_fde *fde = (struct dw_fde*)FDE;
 
   if (pc < fde->initial_loc) {
 }
 
 /* find the FDE for the specified pc address */
-static struct dw_fde *find_fde(gimli_proc_t proc, void *pc)
+static struct dw_fde *find_fde(gimli_proc_t proc, gimli_addr_t pc)
 {
   struct gimli_object_mapping *m;
   struct dw_fde *fde;
 
-  m = gimli_mapping_for_addr(proc, (gimli_addr_t)pc);
+  m = gimli_mapping_for_addr(proc, pc);
   if (!m) {
     return NULL;
   }
     return NULL;
   }
 
-  fde = bsearch(&pc, m->objfile->fdes, m->objfile->num_fdes, sizeof(*fde), search_compare_fde);
+  fde = bsearch(&pc, m->objfile->fdes, m->objfile->num_fdes,
+      sizeof(*fde), search_compare_fde);
   if (fde) {
     return fde;
   }
   }
 
   if (debug) {
-    fprintf(stderr, "\nDWARF: unwind_next pc=%p fp=%p\n",
+    fprintf(stderr, "\nDWARF: unwind_next pc=" PTRFMT " fp=" PTRFMT "\n",
         cur->st.pc, cur->st.fp);
   }
 
   if (!fde) {
     cur->dwarffail = 1;
     if (debug) {
-      fprintf(stderr, "DWARF: no fde for pc=%p\n", cur->st.pc);
+      fprintf(stderr, "DWARF: no fde for pc=" PTRFMT "\n", cur->st.pc);
     }
     return 0;
   }
 
   if (debug) {
-    fprintf(stderr, "FDE: init=" PTRFMT "-" PTRFMT " pc=%p\n",
+    fprintf(stderr, "FDE: init=" PTRFMT "-" PTRFMT " pc=" PTRFMT "\n",
         fde->initial_loc,
         fde->addr_range,
         cur->st.pc);
 
   gimli_proc_t proc;
 
-  void *pc; /* pc in frame 0 */
-  void *fp; /* frame pointer */
-  void *sp; /* stack pointer */
+  gimli_addr_t pc; /* pc in frame 0 */
+  gimli_addr_t fp; /* frame pointer */
+  gimli_addr_t sp; /* stack pointer */
   int lwpid;
 
   int valid;
 #if defined(__linux__)
   struct user_regs_struct regs;
-  //prgregset_t regs;
 #elif defined(sun)
   prgregset_t regs;
   lwpstatus_t lwpst;
 struct gimli_object_mapping {
   gimli_proc_t proc;
   gimli_addr_t base;
-  unsigned long len;
-  unsigned long offset;
+  uint64_t len;
+  uint64_t offset;
   gimli_mapped_object_t objfile;
 };
 
   gimli_proc_t proc,
   const char *objname);
 
-#if SIZEOF_VOIDP == 8
-# define PTRFMT "0x%" PRIx64
-# define PTRFMT_T uint64_t
-#else
-# define PTRFMT "0x%" PRIx32
-# define PTRFMT_T uint32_t
-#endif
+#define PTRFMT "0x%" PRIx64
+#define PTRFMT_T uint64_t
 
 int gimli_process_elf(gimli_mapped_object_t f);
 int gimli_process_dwarf(gimli_mapped_object_t f);
 int gimli_thread_regs_to_dwarf(struct gimli_unwind_cursor *cur);
 void *gimli_reg_addr(struct gimli_unwind_cursor *cur, int col);
 
+static inline int gimli_reg_get(struct gimli_unwind_cursor *cur,
+    int col, gimli_addr_t *val)
+{
+  void **ptr = gimli_reg_addr(cur, col);
+  gimli_addr_t v;
+
+  if (!ptr) {
+    printf("Couldn't find address for register %d\n", col);
+    return 0;
+  }
+  v = (intptr_t)*ptr;
+  if (sizeof(void *) == 4) {
+    v &= 0xffffffff;
+  }
+  *val = v;
+  return 1;
+}
+
+static inline void gimli_reg_set(struct gimli_unwind_cursor *cur,
+    int col, gimli_addr_t val)
+{
+  void **ptr = gimli_reg_addr(cur, col);
+  if (!ptr) {
+    printf("Couldn't find address for register %d\n", col);
+    return;
+  }
+  *ptr = (void*)(intptr_t)val;
+}
+
 char **gimli_init_proctitle(int argc, char **argv);
 void gimli_set_proctitle(const char *fmt, ...);
 void gimli_set_proctitlev(const char *fmt, va_list ap);
   addr = (char*)addr - (p * sizeof(data));
 
   for (i = 0; i < n; i++) {
-    x = gimli_read_mem(proc, (gimli_addr_t)addr, data, sizeof(data));
+    x = gimli_read_mem(proc, (intptr_t)addr, data, sizeof(data));
     printf("%p:   ", addr);
     for (j = 0; j < 4; j++) {
       gimli_addr_t a = data[j];
         return 0;
       }
 
-      if (gimli_read_mem(cur->proc, frame.siptr, &cur->si, sizeof(cur->si))
+      if (gimli_read_mem(cur->proc, (intptr_t)frame.siptr, &cur->si, sizeof(cur->si))
           != sizeof(cur->si)) {
         printf("failed to read siginfo\n");
         return 0;
     cur->st.regs.rsp = uc.uc_mcontext.sp;
     cur->st.regs.rip = uc.uc_mcontext.ip;
 
-    cur->st.fp = (void*)cur->st.regs.rsp;
-    cur->st.pc = (void*)cur->st.regs.rip;
-    cur->st.sp = (void*)cur->st.regs.rsp;
+    cur->st.fp = cur->st.regs.rsp;
+    cur->st.pc = cur->st.regs.rip;
+    cur->st.sp = cur->st.regs.rsp;
 
     return 1;
 #else
     gimli_read_mem(cur->proc, cur->st.pc, &a, sizeof(a));
     if (a == 0x0077b858) {
       /* no SA_SIGINFO */
-      char *ptr;
+      gimli_addr_t ptr;
       struct sigcontext sc;
 
       /* Now we need to update our regs based on the sigcontext.
       cur->st.regs.eax = sc.eax;
       cur->st.regs.eip = sc.eip;
 
-      cur->st.fp = (void*)cur->st.regs.ebp;
-      cur->st.sp = (void*)cur->st.regs.esp;
-      cur->st.pc = (void*)cur->st.regs.eip;
+      cur->st.fp = cur->st.regs.ebp;
+      cur->st.sp = cur->st.regs.esp;
+      cur->st.pc = cur->st.regs.eip;
       return 1;
 
     } else {
         printf("failed to read rt_sigframe\n");
         return 0;
       }
-      if (gimli_read_mem(cur->proc, frame.uc, &uc, sizeof(uc))
+      if (gimli_read_mem(cur->proc, (intptr_t)frame.uc, &uc, sizeof(uc))
           != sizeof(uc)) {
         printf("failed to read ucontext\n");
         return 0;
       cur->st.regs.eax = uc.uc_mcontext.gregs[REG_EAX];
       cur->st.regs.eip = uc.uc_mcontext.gregs[REG_EIP];
 
-      cur->st.fp = (void*)cur->st.regs.ebp;
-      cur->st.sp = (void*)cur->st.regs.esp;
-      cur->st.pc = (void*)cur->st.regs.eip;
+      cur->st.fp = cur->st.regs.ebp;
+      cur->st.sp = cur->st.regs.esp;
+      cur->st.pc = cur->st.regs.eip;
 
       return 1;
     }
     return 1;
   }
 
-//printf("dwarf unwind didn't succeed, doing it the hard way\n");
-//printf("fp=%p sp=%p pc=%p\n", c.st.fp, c.st.sp, c.st.pc);
+#if 0
+printf("dwarf unwind didn't succeed, doing it the hard way\n");
+printf("fp=" PTRFMT " sp=" PTRFMT " pc=" PTRFMT "\n", c.st.fp, c.st.sp, c.st.pc);
+#endif
 
   if (c.st.fp) {
-    if (gimli_read_mem(cur->proc, (gimli_addr_t)c.st.fp,
+    if (gimli_read_mem(cur->proc, c.st.fp,
           &frame, sizeof(frame)) != sizeof(frame)) {
       memset(&frame, 0, sizeof(frame));
     }
 //    printf("read frame: fp=%p pc=%p\n", frame.next, frame.retpc);
     /* If we don't appear to be making progress, or we end up in page 0,
      * then assume we're done */
-    if (c.st.fp == frame.next || frame.next == (void*)0 || frame.retpc < (void*)1024) {
+    if (c.st.fp == (intptr_t)frame.next || frame.next == (void*)0 || frame.retpc < (void*)1024) {
       return 0;
     }
-    cur->st.fp = frame.next;
-    cur->st.pc = frame.retpc;
+    cur->st.fp = (intptr_t)frame.next;
+    cur->st.pc = (intptr_t)frame.retpc;
     if (cur->st.pc > 0 && !gimli_is_signal_frame(cur)) {
       cur->st.pc--;
     }
 * Based on original by Claudio Terra for Lua 3.x.
 * With contributions by Roberto Ierusalimschy.
 */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
 #include <sys/stat.h>
 #include <sys/times.h>
 #include <sys/types.h>
       if (addr == s->addr) {
         snprintf(buf, buflen-1, "%s`%s", m->objfile->objname, s->name);
       } else {
-        snprintf(buf, buflen-1, "%s`%s+%lx",
-            m->objfile->objname, s->name, (uintmax_t)(addr - s->addr));
+        snprintf(buf, buflen-1, "%s`%s+%" PRIx64,
+            m->objfile->objname, s->name, (uint64_t)(addr - s->addr));
       }
     } else {
       /* just identify the containing module; the caller will typically
       if (addr == s->addr) {
         snprintf(buf, buflen-1, "%s`%s", m->objfile->objname, s->name);
       } else {
-        snprintf(buf, buflen-1, "%s`%s+%lx",
-            m->objfile->objname, s->name, (uintmax_t)(addr - s->addr));
+        snprintf(buf, buflen-1, "%s`%s+%" PRIx64,
+            m->objfile->objname, s->name, (uint64_t)(addr - s->addr));
       }
     } else {
       snprintf(buf, buflen-1, "%s`" PTRFMT, m->objfile->objname, addr);
         mod->exename,
         frame ? frame->cur.tid : 0,
         frame ? frame->cur.frameno : 0,
-        frame ? frame->cur.st.pc : 0,
+        frame ? (void*)(intptr_t)frame->cur.st.pc : 0,
         frame,
         typename,
         varname,
-        (void*)addr,
+        (void*)(intptr_t)addr,
         size) == GIMLI_ANA_SUPPRESS) {
     return GIMLI_ITER_STOP;
   }
 
   if (gimli_read_mem(data->proc, addr, &tptr,
         sizeof(tptr)) != sizeof(tptr)) {
-    printf("<unable to read %lu bytes at " PTRFMT ">",
-        sizeof(ptr), data->addr);
+    printf("<unable to read %" PRIu32 " bytes at " PTRFMT ">",
+        (uint32_t)sizeof(ptr), data->addr);
     return;
   }
-  ptr = (gimli_addr_t)tptr;
+  ptr = (gimli_addr_t)(intptr_t)tptr;
 
   if (ptr == 0) {
     printf("nil");
 
     mod->ptr.v2->after_print_frame_var(&ana_api,
           mod->exename, data->frame->cur.tid,
-          data->frame->cur.frameno, data->frame->cur.st.pc,
+          data->frame->cur.frameno,
+          (void*)(intptr_t)data->frame->cur.st.pc,
           data->frame,
           typename,
           data->var->varname,
-          (void*)data->var->addr,
+          (void*)(intptr_t)data->var->addr,
           size);
   }
   return GIMLI_ITER_CONT;
   /* try to efficiently find a string in the target */
   if (proc->pid == 0) {
     /* easy case is when it's local */
-    return strdup((char*)addr);
+    return strdup((char*)(intptr_t)addr);
   }
 
   /* map in a block at a time and look for the terminator */
   memcpy(&thr->regs, ur, sizeof(*ur));
 
 #ifdef sun
-  thr->fp = (void*)thr->regs[R_FP];
-  thr->pc = (void*)thr->regs[R_PC];
-  thr->sp = (void*)thr->regs[R_SP];
+  thr->fp = thr->regs[R_FP];
+  thr->pc = thr->regs[R_PC];
+  thr->sp = thr->regs[R_SP];
 #elif defined(__linux__)
 # ifdef __x86_64__
-  thr->pc = (void*)thr->regs.rip;
-  thr->sp = (void*)thr->regs.rsp;
-  thr->fp = (void*)thr->regs.rsp;
+  thr->pc = thr->regs.rip;
+  thr->sp = thr->regs.rsp;
+  thr->fp = thr->regs.rsp;
 # else
-  thr->pc = (void*)thr->regs.eip;
-  thr->sp = (void*)thr->regs.esp;
-  thr->fp = (void*)thr->regs.ebp;
+  thr->pc = thr->regs.eip;
+  thr->sp = thr->regs.esp;
+  thr->fp = thr->regs.ebp;
 # endif
 #elif defined(__FreeBSD__)
 #ifdef __x86_64__
-  thr->pc = (void*)thr->regs.r_rip;
-  thr->sp = (void*)thr->regs.r_rsp;
-  thr->fp = (void*)thr->regs.r_rbp;
+  thr->pc = thr->regs.r_rip;
+  thr->sp = thr->regs.r_rsp;
+  thr->fp = thr->regs.r_rbp;
 #else
 # error consult machine/reg.h; probably just want ur->r_eip etc.
-  thr->pc = (void*)thr->regs.eip;
-  thr->sp = (void*)thr->regs.esp;
-  thr->fp = (void*)thr->regs.ebp;
+  thr->pc = thr->regs.eip;
+  thr->sp = thr->regs.esp;
+  thr->fp = thr->regs.ebp;
 #endif
 #endif
 }
   gimli_proc_t proc = pp;
   char *name;
 
-  name = gimli_read_string(proc, (void*)obj->rl_nameaddr);
-  gimli_add_mapping(proc, name, (void*)obj->rl_base, obj->rl_bend - obj->rl_base, 0);
+  name = gimli_read_string(proc, (intptr_t)obj->rl_nameaddr);
+  gimli_add_mapping(proc, name, (intptr_t)obj->rl_base, obj->rl_bend - obj->rl_base, 0);
   free(name);
 
   return 1;
 {
   int i, done = 0, tries = 20;
   td_err_e te;
+  int nthreads;
+  struct gimli_thread_state *thr;
 
 #ifdef sun
   read_rtld_maps(proc);
     return GIMLI_ERR_THREAD_DEBUGGER_INIT_FAILED;
   }
   if (proc->ta) {
-    int nthreads;
-    struct gimli_thread_state *thr;
-
     /* we're going to make two passes over the set of threads; the first pass
      * is to assess the threads and request that they stop.
      *
 
       sleep(1);
     } while (tries--);
-
-  } else {
-    gimli_proc_thread_by_lwpid(proc, proc->pid, 1);
+  }
+  if (nthreads == 0) {
+    thr = gimli_proc_thread_by_lwpid(proc, proc->pid, 1);
+    thr->valid = 1;
+#ifdef __linux__
+    {
+      prgregset_t ur;
+      gimli_ptrace(PTRACE_GETREGS, proc->pid, NULL, ur);
+      gimli_user_regs_to_thread(&ur, thr);
+    }
+#endif
   }
 
   return GIMLI_ERR_OK;
 }
 
+ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, const prfpregset_t *fpregset);
 ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, const prfpregset_t *fpregset)
 {
   return PS_ERR;
 }
 
+ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t gregset);
 ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t gregset)
 {
   return PS_ERR;
 }
 
+ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset);
 ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset)
 {
   return PS_ERR;
 }
 
+pid_t ps_getpid(struct ps_prochandle *ph);
 pid_t ps_getpid(struct ps_prochandle *ph)
 {
   return ph->pid;
 
 #ifndef sun
 ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *obj,
+  const char *name, psaddr_t *symaddr);
+ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *obj,
   const char *name, psaddr_t *symaddr)
 {
   struct gimli_symbol *sym = gimli_sym_lookup(ph, obj, name);
   if (sym) {
-    *symaddr = (psaddr_t)sym->addr;
+    *symaddr = (psaddr_t)(intptr_t)sym->addr;
     return PS_OK;
   }
   return PS_NOSYM;
 #ifndef __FreeBSD__
 int gimli_write_mem(gimli_proc_t proc, gimli_addr_t ptr, const void *buf, int len)
 {
-  int ret = pwrite(proc->proc_mem, buf, len, ptr);
+  off64_t addr;
+  int ret;
+
+  if (sizeof(void*) == 4) {
+    ptr &= 0xffffffff;
+  }
+  addr = ptr;
+  ret = pwrite64(proc->proc_mem, buf, len, addr);
   if (ret < 0) ret = 0;
   return ret;
 }
 
 int gimli_read_mem(gimli_proc_t proc, gimli_addr_t src, void *dest, int len)
 {
-  int ret = pread(proc->proc_mem, dest, len, src);
+  off64_t addr;
+  int ret;
+
+  if (sizeof(void*) == 4) {
+    src &= 0xffffffff;
+  }
+  addr = src;
+  ret = pread64(proc->proc_mem, dest, len, addr);
   if (ret < 0) ret = 0;
   return ret;
 }
 #endif
 
 ps_err_e ps_pread(struct ps_prochandle *h,
+			psaddr_t addr, void *buf, size_t size);
+ps_err_e ps_pread(struct ps_prochandle *h,
 			psaddr_t addr, void *buf, size_t size)
 {
-  return gimli_read_mem(h, (gimli_addr_t)addr, buf, size)
+  return gimli_read_mem(h, (intptr_t)addr, buf, size)
     == size ? PS_OK : PS_BADADDR;
 }
 
 ps_err_e ps_pdread(struct ps_prochandle *h, psaddr_t addr,
+  void *buf, size_t size);
+ps_err_e ps_pdread(struct ps_prochandle *h, psaddr_t addr,
   void *buf, size_t size)
 {
-  return gimli_read_mem(h, (gimli_addr_t)addr, buf, size)
+  return gimli_read_mem(h, (intptr_t)addr, buf, size)
     == size ? PS_OK : PS_BADADDR;
 }
 
 ps_err_e ps_pwrite(struct ps_prochandle *h,
+			psaddr_t addr, const void *buf, size_t size);
+ps_err_e ps_pwrite(struct ps_prochandle *h,
 			psaddr_t addr, const void *buf, size_t size)
 {
-  return gimli_write_mem(h, (gimli_addr_t)addr, buf, size)
+  return gimli_write_mem(h, (gimli_addr_t)(intptr_t)addr, buf, size)
     == size ? PS_OK : PS_BADADDR;
 }
 
 ps_err_e ps_pdwrite(struct ps_prochandle *h, psaddr_t addr,
+  const void *buf, size_t size);
+ps_err_e ps_pdwrite(struct ps_prochandle *h, psaddr_t addr,
   const void *buf, size_t size)
 {
-  return gimli_write_mem(h, (gimli_addr_t)addr, buf, size)
+  return gimli_write_mem(h, (gimli_addr_t)(intptr_t)addr, buf, size)
     == size ? PS_OK : PS_BADADDR;
 }
 
 #ifdef __linux__
+ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset);
 ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset)
 {
   if (0 == gimli_ptrace(PTRACE_GETREGS, lwpid, NULL, gregset)) {
 }
 #endif
 
+void ps_plog(const char *fmt, ...);
 void ps_plog(const char *fmt, ...)
 {
   va_list ap;
     /* copy out register set */
     memcpy(cur->st.regs, uc.uc_mcontext.gregs, sizeof(cur->st.regs));
     /* update local copy */
-    cur->st.fp = (void*)cur->st.regs[R_FP];
-    cur->st.pc = (void*)cur->st.regs[R_PC];
-    cur->st.sp = (void*)cur->st.regs[R_SP];
+    cur->st.fp = cur->st.regs[R_FP];
+    cur->st.pc = cur->st.regs[R_PC];
+    cur->st.sp = cur->st.regs[R_SP];
     /* registers are all good for dwarf */
     cur->dwarffail = 0;
     return 1;
       memset(&frame, 0, sizeof(frame));
     }
 
-    if (c.st.fp == (void*)frame.fr_savfp) {
+    if (c.st.fp == frame.fr_savfp) {
       return 0;
     }
-    cur->st.fp = (void*)frame.fr_savfp;
-    cur->st.pc = (void*)frame.fr_savpc;
+    cur->st.fp = frame.fr_savfp;
+    cur->st.pc = frame.fr_savpc;
 
     if (cur->st.pc > 0 && !gimli_is_signal_frame(cur)) {
       cur->st.pc--;
           cur->st.regs[R_FP]);
       }
     }
-    cur->st.fp = (void*)cur->st.regs[R_FP];
-    cur->st.pc = (void*)cur->st.regs[R_PC];
-    cur->st.sp = (void*)cur->st.regs[R_SP];
+    cur->st.fp = cur->st.regs[R_FP];
+    cur->st.pc = cur->st.regs[R_PC];
+    cur->st.sp = cur->st.regs[R_SP];
     cur->dwarffail = 0;
 #endif
 
        * that we're unwinding to that context.
        * To do this, we force in a -1 instruction pointer, which coincides
        * with the non-dwarf aware way of detecting a signal frame */
-      cur->st.pc = (void*)-1;
+      cur->st.pc = -1;
     }
     return 1;
   }
 #elif defined(__i386)
   if (((intptr_t)cur->st.fp + sizeof(struct frame) +
       (3 * sizeof(greg_t)) == cur->st.lwpst.pr_oldcontext) ||
-      (cur->st.pc == (void*)-1 && cur->st.lwpst.pr_oldcontext != 0)) {
+      (cur->st.pc == -1 && cur->st.lwpst.pr_oldcontext != 0)) {
     struct {
       int signo;
       siginfo_t *siptr;
       ucontext_t *ucptr;
     } frame;
 
-    gimli_read_mem(cur->proc, (char*)cur->st.lwpst.pr_oldcontext - sizeof(frame),
-      &frame, sizeof(frame));
+    gimli_read_mem(cur->proc,
+        (intptr_t)cur->st.lwpst.pr_oldcontext - sizeof(frame),
+        &frame, sizeof(frame));
 
-    if (!frame.siptr || gimli_read_mem(cur->proc, frame.siptr,
+    if (!frame.siptr || gimli_read_mem(cur->proc, (intptr_t)frame.siptr,
           &cur->si, sizeof(cur->si)) != sizeof(cur->si)) {
       memset(&cur->si, 0, sizeof(cur->si));
       cur->si.si_signo = frame.signo;
     return 1;
   }
 #endif
-  if (cur->st.pc == (void*)-1) {
+  if (cur->st.pc == -1) {
     return 1;
   }
   return 0;
   if (use_fault_addr) {
     const char *name;
 
-    name = gimli_pc_sym_name(proc, (gimli_addr_t)si->si_addr,
+    name = gimli_pc_sym_name(proc, (intptr_t)si->si_addr,
         namebuf, sizeof(namebuf));
     if (name && strlen(name)) {
       snprintf(addrbuf, sizeof(addrbuf), " (%s)", name);
     } else {
-      snprintf(addrbuf, sizeof(addrbuf), " (" PTRFMT ")", (intptr_t)si->si_addr);
+      snprintf(addrbuf, sizeof(addrbuf), " (" PTRFMT ")",
+          (gimli_addr_t)(intptr_t)si->si_addr);
     }
   }