patch for UPS/Solaris/x86.

"G. Narendran" <[email protected]> Fri, 21 Nov 2003 17:51:28 +0530
Newsgroups gmane.comp.debugging.ups.user
Message-ID <[email protected]>
Hi,

We had earlier reported progress in porting UPS to Solaris/x86.
Here is the patch for the port. We would welcome your feedback on
the same.

Files attached:
ups-3.38-b2-solx86.patch     The patch for UPS/Solaris/x86
ups-bugs.txt                 UPS bugs detected during the port


Build instructions:
gtar -xzvf ups-3.38-beta2.tar.gz
cd ups-3.38-beta2
patch -cbi ups-3.38-b2-solx86.patch
./configure                         # + any options
make                                # dmake or gmake
make install                        # as root

Configurations tested:
. Both i386-pc-solaris2.9 (target) and sparc-sun-solaris2.9
  (reference).
. Both Sun ONE Studio 8 cc, and gcc (2.95.3) (both UPS and the
  debugged programs were built and tested with both the compilers.)
. Test programs:
  - all in the ups/tests directory.
  - additional programs to test specific scenarios (wrong multiple
    execution of bp code (see below), watch points etc.,)
  - UPS itself.
  - For a taste of really large application, with a large number of
    dynamically loaded modules etc.,: the Ximian Evolution mail
    client for Solaris/x86 (this also tested stoppage at solib
    event.)

  UPS has been found quite stable under the above tests.

Summary of the fixes:
 . On x86, PC is incremented even when the int3 (0xcc) instruction is
   executed. So when resuming after a breakpoint processing, it is
   not merely sufficient to replace the bp opcode with the original
   opcode. The PC must be rolled back by 1 and the kernel instructed
   to restart from the decremented vaddr (ao_procfs.c)
 . register number fixes:
   - for correct display of register variables etc., added gcc
     register translation for procfs (ao_symload.c)
   - to get indirect function calls working (ao_target.c)
*  - for correct decoding of PLT 'jmp *off(%ebx)' (ao_elflib.c,
     ao_stack.c)
*. fixed bug in the addr_cmp function for qsort, to solve UPS crashes
   on a large application (evolution) with many dynamic solibs
   (ao_elflib.c)
*. fix to prevent UPS from executing twice the bp interpreted code
   that results in the first stop (trun_ss.c)
 . to get 'next' working (ao_target.c)
 . to skip _start etc., symbols in stack trace (ao_stack.c)
 . fix for struct passed by value (ao_symparse.c)
 . changes to resolve build issues (see the patch)
 . new define ARCH_SOLARISX86 added (configure.in, ifdefs.h.in)

Those marked with * are quite possibly UPS bugs on other platforms
as well, but the fixes have been wrapped in ARCH_SOLARISX86 as we
didn't have the test environment for the other platforms. The file
ups-bugs.txt describes them in case there is interest in fixing them
for the other platforms.

We intentionally left out fixing the following:
 . While attempting to display a 'register long long' variable UPS
   heuristically determines the register number for second word
   based on the regno. for the first word. As we could only guess
   which registers gcc would use, and as even this might not match
   cc's placement, we didn't alter the code. Any suggestions for
   this is welcome.

---x---
Narendran Gopalakrishnan
SIP Technologies & Exports Ltd
G4, Elnet Software City, CPT Road
Taramani, Chennai 600 113
India

Phone: +91-44-22541401
       +91-44-22541031

Fax  : +91-44-22541475

Website: http://www.siptech.com


.
ups-3.38-b2-solx86.patch (text/plain, 14 KB)
*** ./ups/ao_elfcore.c.orig	2003-04-01 17:44:01.000000000 +0530
--- ./ups/ao_elfcore.c	2003-11-20 16:17:09.000000000 +0530
***************
*** 65,71 ****
  #include "ao_elfread.h"
  #include "ao_elfcore.h"
  
! #if (defined ARCH_LINUX386)
  #if HAVE_SYS_REG_H
  #include <sys/reg.h>
  #endif
--- 65,71 ----
  #include "ao_elfread.h"
  #include "ao_elfcore.h"
  
! #if (defined ARCH_LINUX386) || (defined ARCH_SOLARISX86)
  #if HAVE_SYS_REG_H
  #include <sys/reg.h>
  #endif
***************
*** 464,470 ****
--- 464,474 ----
  	    elf_core_greg_t *iregs = (elf_core_greg_t *)regs;
  	    if (regno < 0 || regno >= sizeof(elf_core_gregset_t)/sizeof(elf_core_greg_t))
  		    panic("bad regno in egcr");
+ #if defined(AO_USE_PTRACE) /* x86_gcc_register not defined otherwise */
  	    addr = (taddr_t)&(iregs[x86_gcc_register(regno)]);
+ #else
+ 	    addr = (taddr_t)&(iregs[regno]);
+ #endif /* ! AO_USE_PTRACE */
  	}
      } /* switch */
  #else
*** ./ups/ao_elflib.c.orig	2003-07-16 15:30:24.000000000 +0530
--- ./ups/ao_elflib.c	2003-11-20 16:17:53.000000000 +0530
***************
*** 1595,1603 ****
--- 1595,1608 ----
    const addr_t *addr1 = addr1p;
    const addr_t *addr2 = addr2p;
     
+ #if defined(ARCH_SOLARISX86)
+   /* 3-way return needed by qsort. And we don't need that '!addr1' etc., :-) */
+   return (addr1->addr > addr2->addr) ? -1 : (addr1->addr < addr2->addr);
+ #else
    if (!addr1 || !addr2)
      return 1;
    return addr1->addr < addr2->addr;
+ #endif
  }
  
  char *
***************
*** 1755,1761 ****
--- 1760,1770 ----
     unsigned char jmp[6];
     taddr_t newpc;
  
+ #if defined(ARCH_SOLARISX86)
+    ebx = xp_getreg(xp, 8); /* EBX is 8 on Solaris/x86 */
+ #else
     ebx = xp_getreg(xp, 3);
+ #endif
     
     xp_read_data(xp, pc, (char *)jmp, 6);
  
*** ./ups/ao_procfs.c.orig	2002-10-26 18:35:00.000000000 +0530
--- ./ups/ao_procfs.c	2003-11-20 15:59:55.000000000 +0530
***************
*** 429,434 ****
--- 429,437 ----
  			  stopres = SR_USER; /* out of a bad jump to here */
  			else
  			  stopres = SR_BPT;
+ #if defined(ARCH_SOLARISX86)
+ 			--status.pr_reg[R_PC];  /* roll back PC on Solaris/x86 */
+ #endif
  			pi->clear_fault_on_resume = TRUE;
  			break;
  		case FLTTRACE:
***************
*** 877,882 ****
--- 880,892 ----
  		prrun.pr_vaddr = (caddr_t)restart_pc;
  		flags |= PRSVADDR;
  	}
+ #if defined(ARCH_SOLARISX86)
+ 	else if (ip->ip_stopres == SR_BPT) {
+ 		/* restart from the rolled back PC */
+ 		prrun.pr_vaddr = (caddr_t)ip->ip_restart_pc;
+ 		flags |= PRSVADDR;
+ 	}
+ #endif
  	
  	prrun.pr_flags = flags;
  
*** ./ups/ao_stack.c.orig	2002-11-28 20:54:35.000000000 +0530
--- ./ups/ao_stack.c	2003-11-20 16:18:24.000000000 +0530
***************
*** 438,444 ****
  			break;
  		}
  #endif
! #ifdef ARCH_LINUX386
  		if ((strcmp(f->fu_demangled_name, "_entry") == 0) ||
  		    (strcmp(f->fu_demangled_name, "_start") == 0) ||
  		    (strcmp(f->fu_demangled_name, "__libc_start_main") == 0)) {
--- 438,444 ----
  			break;
  		}
  #endif
! #if defined(ARCH_LINUX386) || defined(ARCH_SOLARISX86)
  		if ((strcmp(f->fu_demangled_name, "_entry") == 0) ||
  		    (strcmp(f->fu_demangled_name, "_start") == 0) ||
  		    (strcmp(f->fu_demangled_name, "__libc_start_main") == 0)) {
***************
*** 518,524 ****
--- 518,528 ----
  					if (ebxoffset)
  						dread(xp, sp + offset + ebxoffset, (char *)&ebx, sizeof(ebx));
  					else
+ #if defined(ARCH_SOLARISX86)
+ 						ebx = xp_getreg(xp, EBX); /* fix for Solaris/x86 */
+ #else
  						ebx = xp_getreg(xp, 3);
+ #endif
  
  					if (ebpoffset) {
  						if (dread(xp, sp + offset + ebpoffset, (char *)&fp, sizeof(fp)) != 0 || !fp)
***************
*** 1218,1224 ****
  		return 0;
  	}
  #endif
! #ifdef ARCH_386
  	reg = x86_gcc_register(reg);
  #endif
  
--- 1222,1228 ----
  		return 0;
  	}
  #endif
! #if defined(ARCH_386) && defined(AO_USE_PTRACE)
  	reg = x86_gcc_register(reg);
  #endif
  
*** ./ups/ao_symload.c.orig	2002-11-04 20:26:19.000000000 +0530
--- ./ups/ao_symload.c	2003-11-21 09:38:08.000000000 +0530
***************
*** 44,49 ****
--- 44,55 ----
  #	endif
  #endif
  
+ #if defined(ARCH_SOLARISX86)
+ #if HAVE_SYS_REG_H
+ #include <sys/reg.h> /* defines for sol_x86_gcc_register */
+ #endif
+ #endif
+ 
  #include <local/wn.h>
  #include <local/ukcprog.h>
  #include <mtrprog/strcache.h>
***************
*** 90,95 ****
--- 96,104 ----
  #ifdef AO_ELF
  static bool static_addrs_relative PROTO((Compiler_type compiler_type));
  #endif
+ #if defined(ARCH_SOLARISX86)
+ static int sol_x86_gcc_register PROTO((int regno));
+ #endif
  
  void display_message PROTO((const char *mesg));
  
***************
*** 975,981 ****
  func_t *f;
  unsigned long val;
  {
! #if defined(ARCH_386) && defined(OS_SUNOS)
  	return val;
  #else
  #ifdef AO_ELF
--- 984,990 ----
  func_t *f;
  unsigned long val;
  {
! #if defined(ARCH_SOLARISX86)
  	return val;
  #else
  #ifdef AO_ELF
***************
*** 983,989 ****
  #else
  	return AO_FIDATA(f->fu_fil)->stf_addr + val;
  #endif /* !AO_ELF */
! #endif /* !(ARCH_386 && OS_SUNOS) */
  }
  
  #ifdef AO_ELF
--- 992,998 ----
  #else
  	return AO_FIDATA(f->fu_fil)->stf_addr + val;
  #endif /* !AO_ELF */
! #endif /* !(ARCH_SOLARISX86) */
  }
  
  #ifdef AO_ELF
***************
*** 995,1000 ****
--- 1004,1029 ----
  }
  #endif /* AO_ELF */
  
+ #if defined(ARCH_SOLARISX86)
+ /* The following separated out of ao_pt_regs.c as we use procfs instead.
+  * This is copied from x86_gcc_register for ARCH_LINUX386. But some
+  * of the registers in Solaris/x86 sys/reg.h don't find a mention here,
+  * and some are extraneous. TODO: Check gcc code/doc for Solaris/x86
+  * to see if this translation is complete.
+  */
+ 
+ static int
+ sol_x86_gcc_register(regno)
+ int regno;
+ {
+ 	static int regmap[] = {
+ 		EAX, ECX, EDX, EBX, UESP, EBP, ESI, EDI,
+ 		EIP, EFL, CS, SS, DS, ES, FS, GS /*, ORIG_EAX */
+ 	};
+ 	return regmap[regno];
+ }
+ #endif
+ 
  block_t *
  ao_get_fu_blocks(f)
  func_t *f;
***************
*** 1450,1455 ****
--- 1479,1495 ----
  			    !(stf->stf_compiler_type == CT_CC &&
  			      f->fu_fil->fi_language == LANG_CC))
  			  addr += ast->st_base_address;
+ #if defined(ARCH_SOLARISX86)
+ 			/* We have to translate what gcc has set in the symbol
+ 			 * table to match the registers on Solaris/x86. Very
+ 			 * similar to the x86_gcc_register, except that we
+ 			 * translate right where the symbol is read.
+ 			 */
+ 			else if (class == CL_REG &&
+ 			    (stf->stf_compiler_type == CT_GNU_CC ||
+ 			      stf->stf_compiler_type == CT_GNU_F77))
+ 			  addr = sol_x86_gcc_register(addr);
+ #endif
  
  			v = ci_make_var(ap, name, class, type, addr);
  			v->va_language = stf->stf_language;
*** ./ups/ao_symparse.c.orig	2002-11-28 21:56:20.000000000 +0530
--- ./ups/ao_symparse.c	2003-11-20 16:01:46.000000000 +0530
***************
*** 832,838 ****
  	 *  Modern compilers support passing struct/union by value.
  	 *  Still works on Solaris 2 so keep for OS_SUNOS.
  	 */
! #ifdef OS_SUNOS
  	if ((class == CL_ARG) && (rtype->ty_code == TY_STRUCT || rtype->ty_code == TY_UNION))
  		class = CL_REF; 
  #endif
--- 832,842 ----
  	 *  Modern compilers support passing struct/union by value.
  	 *  Still works on Solaris 2 so keep for OS_SUNOS.
  	 */
! #if defined(OS_SUNOS) && !defined(ARCH_386)
! 	/*  7Nov3: on x86, this fix is needed for neither cc nor gcc.
! 	 *         on SPARC, it is needed for cc (gcc seems to use
! 	 *         CL_AUTO for CL_ARG as well.)
! 	 */
  	if ((class == CL_ARG) && (rtype->ty_code == TY_STRUCT || rtype->ty_code == TY_UNION))
  		class = CL_REF; 
  #endif
*** ./ups/ao_target.c.orig	2003-07-16 15:30:28.000000000 +0530
--- ./ups/ao_target.c	2003-11-21 16:56:48.000000000 +0530
***************
*** 640,646 ****
  target_t *xp;
  int rlink_reg;
  {
! #if defined(ARCH_SUN3) || defined(ARCH_CLIPPER) || defined(ARCH_BSDI386)  || defined(ARCH_LINUX386)
  	taddr_t sp, retaddr;
  
  	sp = xp_getreg(xp, UPSREG_SP);
--- 640,647 ----
  target_t *xp;
  int rlink_reg;
  {
! #if defined(ARCH_SUN3) || defined(ARCH_CLIPPER) || \
!    defined(ARCH_BSDI386) || defined(ARCH_LINUX386) || defined(ARCH_SOLARISX86)
  	taddr_t sp, retaddr;
  
  	sp = xp_getreg(xp, UPSREG_SP);
***************
*** 987,992 ****
--- 988,997 ----
  #define ALIGN_STACK(n)	((n) & ~(unsigned)07)
  #endif
  
+ #if defined(ARCH_SOLARISX86)
+ #define RETURN_REGNO	11	/* EAX is 11 on Solaris/x86 */
+ #endif
+ 
  #ifndef N_REG_ARGS
  #define N_REG_ARGS	0
  #endif
***************
*** 1282,1288 ****
  	}
  #endif /* ARCH_VAX */
  #if defined(ARCH_SUN3) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_BSDI386) || defined(ARCH_LINUX386)
  	sp -= 4;
  	if (ps_write_data(ip, sp, (char *)&retpc, sizeof(retpc)) != 0) {
  		*p_mesg = "Can't push return address";
--- 1287,1293 ----
  	}
  #endif /* ARCH_VAX */
  #if defined(ARCH_SUN3) || defined(ARCH_CLIPPER) || \
!     defined(ARCH_BSDI386) || defined(ARCH_LINUX386) || defined(ARCH_SOLARISX86)
  	sp -= 4;
  	if (ps_write_data(ip, sp, (char *)&retpc, sizeof(retpc)) != 0) {
  		*p_mesg = "Can't push return address";
***************
*** 1316,1322 ****
  	ps_setreg(ip, UPSREG_SP, sp);
  #endif /* ARCH_VAX */
  #if defined(ARCH_SUN3) || defined(ARCH_BSDI386) || \
!     defined(ARCH_LINUX386)
  	ps_setreg(ip, UPSREG_SP, sp);
  #endif
  #ifdef ARCH_MIPS
--- 1321,1327 ----
  	ps_setreg(ip, UPSREG_SP, sp);
  #endif /* ARCH_VAX */
  #if defined(ARCH_SUN3) || defined(ARCH_BSDI386) || \
!     defined(ARCH_LINUX386) || defined(ARCH_SOLARISX86)
  	ps_setreg(ip, UPSREG_SP, sp);
  #endif
  #ifdef ARCH_MIPS
***************
*** 1390,1397 ****
--- 1395,1406 ----
  	*p_res = xp_getreg(xp, RETURN_REGNO);
  #ifdef ARCH_386
  	if (restype == TY_LONGLONG || restype == TY_ULONGLONG)
+ #if defined(ARCH_SOLARISX86)
+ 		p_res[1] = xp_getreg(xp, 9); /* EDX is 9 on Solaris/x86 */
+ #else
  		p_res[1] = xp_getreg(xp, 2);
  #endif
+ #endif
  
  	/*  Copy back any stuff we copied into the target's core.
  	 */
*** ./ups/cx_libfuncs.h.orig	2002-10-26 18:36:36.000000000 +0530
--- ./ups/cx_libfuncs.h	2003-11-20 15:21:11.000000000 +0530
***************
*** 149,154 ****
--- 149,160 ----
  #endif
  #endif /* OS_SUNOS_4 */
  
+ #ifdef OS_SUNOS
+ #if HAVE_DOPRNT
+ int _doprnt(void);
+ #endif
+ #endif /* OS_SUNOS */
+ 
  #endif /* WANT_DECLS */
  
  
*** ./ups/trun_ss.c.orig	2003-06-06 21:54:42.000000000 +0530
--- ./ups/trun_ss.c	2003-11-20 16:06:27.000000000 +0530
***************
*** 155,161 ****
--- 155,176 ----
  			if (rtype != RT_CONT)
  				panic("bad rtype in dx_run_target");
  			stopres = dx_start(xp);
+ #if defined(ARCH_SOLARISX86)
+ 			/* Fix on Solaris/x86 for the following bug: dx_start has
+ 			 * inturn called dx_run_target_ss already. So when it returns
+ 			 * SR_BPT the bp code has already been executed once. If we
+ 			 * don't break on SR_BPT, the bp code is executed again.
+ 			 * For e.g., after the following bp code in the ups window: 
+ 			 *
+ 			 * i = 42;
+ 			 * ++i && #stop;
+ 			 *
+ 			 * i becomes 44.
+ 			 */
+ 			if (!target_process_exists(xp) || stopres == SR_WPT || stopres == SR_BPT)
+ #else
  			if (!target_process_exists(xp) || stopres == SR_WPT)
+ #endif
  				break;
  			sig = 0;
  			if (rtype == RT_CONT &&
*** ./README.orig	2002-10-26 18:31:33.000000000 +0530
--- ./README	2003-11-20 15:44:48.000000000 +0530
***************
*** 85,90 ****
--- 85,91 ----
  	------------		----------		
  	SPARC			Solaris 2.X, Solaris 7, Solaris 8
  	SPARC			SunOS 4.X
+ 	Intel x86		Solaris 2.X
  	Intel x86		FreeBSD 3.x, 4.x (ELF)
  	Intel x86		Linux 2.2.x (ELF)
  
*** ./configure.in.orig	2003-08-29 20:18:50.000000000 +0530
--- ./configure.in	2003-11-20 15:49:28.000000000 +0530
***************
*** 768,774 ****
      i386-sun-sunos4.0.2)ups_arch=ARCH_SUN386 ;; # Obsolete Sun386i
      m68k-*-sunos*)	ups_arch=ARCH_SUN3 ;;
      sparc-*-*)		ups_arch=ARCH_SUN4 ;;
!     i?86-*-solaris*)	ups_arch=ARCH_386 ;; # Not yet supported
      i?86-*-freebsd1*)	ups_arch=ARCH_BSDI386 ;;
      i?86-*-freebsd*)	ups_arch=ARCH_FREEBSD386 ;;
      i?86-*-openbsd*)	ups_arch=ARCH_OPENBSD386 ;;
--- 768,774 ----
      i386-sun-sunos4.0.2)ups_arch=ARCH_SUN386 ;; # Obsolete Sun386i
      m68k-*-sunos*)	ups_arch=ARCH_SUN3 ;;
      sparc-*-*)		ups_arch=ARCH_SUN4 ;;
!     i?86-*-solaris*)	ups_arch=ARCH_SOLARISX86 ;;
      i?86-*-freebsd1*)	ups_arch=ARCH_BSDI386 ;;
      i?86-*-freebsd*)	ups_arch=ARCH_FREEBSD386 ;;
      i?86-*-openbsd*)	ups_arch=ARCH_OPENBSD386 ;;
*** ./ifdefs.h.in.orig	2003-08-30 23:53:17.000000000 +0530
--- ./ifdefs.h.in	2003-11-20 16:10:58.000000000 +0530
***************
*** 43,48 ****
--- 43,49 ----
   *  ARCH_ALPHA		- DEC Alpha
   *
   *  ARCH_386		- any Intel x86
+  *  ARCH_SOLARISX86	- Solaris (x86)
   *  ARCH_LINUX386	- Linux (x86)
   *  ARCH_BSDI386	- should be BSD/OS (x86), actually any BSD (x86)
   *  ARCH_FREEBSD386	- FreeBSD (x86)
***************
*** 79,84 ****
--- 80,86 ----
  #undef ARCH_SUN3
  #undef ARCH_SUN4
  #undef ARCH_386
+ #undef ARCH_SOLARISX86
  #undef ARCH_FREEBSD386
  #undef ARCH_OPENBSD386
  #undef ARCH_NETBSD386
***************
*** 119,125 ****
   *  Any 386 ?
   * ---------------------------------------------------------------------------
   */
! #if (ARCH_BSDI386) || (ARCH_LINUX386)
  #define ARCH_386		1
  #endif
  
--- 121,127 ----
   *  Any 386 ?
   * ---------------------------------------------------------------------------
   */
! #if (ARCH_BSDI386) || (ARCH_LINUX386) || (ARCH_SOLARISX86)
  #define ARCH_386		1
  #endif
  
*** ./configure.orig	2003-08-29 20:18:50.000000000 +0530
--- ./configure	2003-11-20 15:50:13.000000000 +0530
***************
*** 12177,12183 ****
      i386-sun-sunos4.0.2)ups_arch=ARCH_SUN386 ;; # Obsolete Sun386i
      m68k-*-sunos*)	ups_arch=ARCH_SUN3 ;;
      sparc-*-*)		ups_arch=ARCH_SUN4 ;;
!     i?86-*-solaris*)	ups_arch=ARCH_386 ;; # Not yet supported
      i?86-*-freebsd1*)	ups_arch=ARCH_BSDI386 ;;
      i?86-*-freebsd*)	ups_arch=ARCH_FREEBSD386 ;;
      i?86-*-openbsd*)	ups_arch=ARCH_OPENBSD386 ;;
--- 12177,12183 ----
      i386-sun-sunos4.0.2)ups_arch=ARCH_SUN386 ;; # Obsolete Sun386i
      m68k-*-sunos*)	ups_arch=ARCH_SUN3 ;;
      sparc-*-*)		ups_arch=ARCH_SUN4 ;;
!     i?86-*-solaris*)	ups_arch=ARCH_SOLARISX86 ;;
      i?86-*-freebsd1*)	ups_arch=ARCH_BSDI386 ;;
      i?86-*-freebsd*)	ups_arch=ARCH_FREEBSD386 ;;
      i?86-*-openbsd*)	ups_arch=ARCH_OPENBSD386 ;;
ups-bugs.txt (text/plain, 712 B)
UPS bugs, found during the Solaris/x86 porting (they have not been
fixed for platforms other than Solaris/x86 for lack of test
environment.) 

- The interpreted code for the first breakpoint that results in a
  stop is executed twice. For example, after the following:

  i = 42;
  ++i && #stop;

  i incorrectly becomes 44 (trun_ss.c:155)

- Wrong reg no. for EBX while decoding PLT (ao_elflib.c:1755,
  ao_stack.c:528) (It seems to be using ESI instead of EBX.) This
  causes ups/tests/assertion test scenario to fail.

- The addr_cmp for qsort function should make a 3-way return
  (-1,0,1) (ao_elflib.c:1595) The current function causes qsort to
  corrupt memory and cause crashes when figuring out solibs.