aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog22
-rw-r--r--gdb/acconfig.h9
-rw-r--r--gdb/breakpoint.c2
-rw-r--r--gdb/config.in9
-rw-r--r--gdb/configure.in23
-rw-r--r--gdb/core-sol2.c66
-rw-r--r--gdb/sol-thread.c29
-rw-r--r--gdb/solib.c207
-rw-r--r--gdb/valops.c4
9 files changed, 330 insertions, 41 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 500c938..c7360e1 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,25 @@
+2000-08-29 Michael Snyder <msnyder@seadog.cygnus.com>
+
+ * valops.c (value_cast): Indentation fix-up.
+ * acconfig.h (HAVE_PRGREGSET32_T, HAVE_PRFPREGSET32_T,
+ HAVE_STRUCT_LINK_MAP32): New configure macros.
+ * config.in: Ditto.
+ * configure.in: Test for the above new macros.
+ * breakpoint.c: Update copyright date.
+ * core-sol2.c: Include v9/sys/privregs.h directly to
+ work around a bug in Sun's Solaris 8 header files.
+ (fetch_core_registers): Use the above new configure macros to
+ handle cross-debugging of 32-bit core files on a 64-bit host.
+ * sol-thread.c (ps_pdmodel) New function.
+ (rw_common): For debugging of 32-bit apps on a 64-bit host,
+ truncate addresses to 32 bits.
+ * solib.c (solib_extract_address): Functionize. Make 32/64 aware.
+ (LM_ADDR, LM_NEXT, LM_NAME): Ditto.
+ (IGNORE_FIRST_LINK_MAP): Ditto.
+ (first_link_map_member): Make 32/64 aware.
+ (open_symbol_file_object): Ditto.
+ (current_sos): Ditto.
+
2000-08-29 Michael Snyder <msnyder@cleaver.cygnus.com>
* i386-linux-nat.c (i386_linux_skip_solib_resolver,
diff --git a/gdb/acconfig.h b/gdb/acconfig.h
index fea655c..ba09e81 100644
--- a/gdb/acconfig.h
+++ b/gdb/acconfig.h
@@ -31,6 +31,15 @@
/* Define if <sys/procfs.h> has psaddr_t. */
#undef HAVE_PSADDR_T
+/* Define if <sys/procfs.h> has prgregset32_t. */
+#undef HAVE_PRGREGSET32_T
+
+/* Define if <sys/procfs.h> has prfpregset32_t. */
+#undef HAVE_PRFPREGSET32_T
+
+/* Define if <sys/link.h> has struct link_map32 */
+#undef HAVE_STRUCT_LINK_MAP32
+
/* Define if the prfpregset_t type is broken. */
#undef PRFPREGSET_T_BROKEN
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 4633373..489aad2 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1,5 +1,5 @@
/* Everything about breakpoints, for GDB.
- Copyright 1986, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+ Copyright 1986, 87, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 1999, 2000
Free Software Foundation, Inc.
This file is part of GDB.
diff --git a/gdb/config.in b/gdb/config.in
index bbeebbe..e86239c 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -246,6 +246,9 @@
/* Define if you have the <link.h> header file. */
#undef HAVE_LINK_H
+/* Define if <link.h> defines struct link_map32. */
+#undef HAVE_STRUCT_LINK_MAP32
+
/* Define if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
@@ -417,6 +420,12 @@
/* Define if <sys/procfs.h> has prfpregset_t. */
#undef HAVE_PRFPREGSET_T
+/* Define if <sys/procfs.h> has prgregset32_t. */
+#undef HAVE_PRGREGSET32_T
+
+/* Define if <sys/procfs.h> has prfpregset32_t. */
+#undef HAVE_PRFPREGSET32_T
+
/* Define if <sys/procfs.h> has lwpid_t. */
#undef HAVE_LWPID_T
diff --git a/gdb/configure.in b/gdb/configure.in
index 6dfd7f1..6dda43a 100644
--- a/gdb/configure.in
+++ b/gdb/configure.in
@@ -229,9 +229,32 @@ if test "$ac_cv_header_sys_procfs_h" = yes; then
BFD_HAVE_SYS_PROCFS_TYPE(fpregset_t)
BFD_HAVE_SYS_PROCFS_TYPE(prgregset_t)
BFD_HAVE_SYS_PROCFS_TYPE(prfpregset_t)
+ BFD_HAVE_SYS_PROCFS_TYPE(prgregset32_t)
+ BFD_HAVE_SYS_PROCFS_TYPE(prfpregset32_t)
BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t)
BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t)
+ dnl Check for struct link_map32 type, which allows a 64-bit Solaris
+ dnl debugger to debug a 32-bit Solaris app with 32-bit shared libraries.
+
+ AC_MSG_CHECKING(for struct link_map32 in sys/link.h)
+ AC_CACHE_VAL(gdb_cv_have_struct_link_map32,
+ [AC_TRY_RUN([#define _SYSCALL32
+ #include <sys/link.h>
+ int main()
+ {
+ if (sizeof (struct link_map32) > 0)
+ return 1;
+ return 0;
+ }],
+ gdb_cv_have_struct_link_map32=no,
+ gdb_cv_have_struct_link_map32=yes,
+ gdb_cv_have_struct_link_map32=yes)])
+ AC_MSG_RESULT($gdb_cv_have_struct_link_map32)
+ if test $gdb_cv_have_struct_link_map32 = yes; then
+ AC_DEFINE(HAVE_STRUCT_LINK_MAP32)
+ fi
+
dnl Check for broken prfpregset_t type
dnl For Linux/i386, glibc 2.1.3 was released with a bogus
diff --git a/gdb/core-sol2.c b/gdb/core-sol2.c
index 59aab7b..5a32c04 100644
--- a/gdb/core-sol2.c
+++ b/gdb/core-sol2.c
@@ -1,5 +1,5 @@
/* Machine independent support for Solaris 2 core files for GDB.
- Copyright 1994 Free Software Foundation, Inc.
+ Copyright 1994, 2000 Free Software Foundation, Inc.
This file is part of GDB.
@@ -26,7 +26,15 @@
This file combines the core register fetching from core-regset.c
and sparc-nat.c to be able to read both flavours. */
+/* for Sparc64 cross Sparc32 */
+#define _SYSCALL32
#include "defs.h"
+
+#if defined (__sparcv9)
+/* Fails to get included by the Solaris system header files. */
+# include <v9/sys/privregs.h>
+#endif
+
#include <time.h>
#include <sys/types.h>
#include <sys/regset.h>
@@ -55,19 +63,36 @@ static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
CORE_ADDR reg_addr)
{
- prgregset_t prgregset;
- prfpregset_t prfpregset;
+ int i;
if (which == 0)
{
- if (core_reg_size == sizeof (prgregset))
+ prgregset_t prgregset;
+
+ if (core_reg_size == sizeof (prgregset_t))
{
memcpy ((char *) &prgregset, core_reg_sect, sizeof (prgregset));
supply_gregset (&prgregset);
}
+#if defined (HAVE_PRGREGSET32_T)
+ /* 32-bit corefile, 64-bit debugger. */
+ else if (core_reg_size == sizeof (prgregset32_t))
+ {
+ prgreg32_t *core_gregs;
+
+ /* Can't use memcpy here, because the core file contains
+ 32-bit regs; supply_register expects 64-bit regs. */
+ core_gregs = (prgreg32_t *) core_reg_sect;
+ for (i = 0; i < NPRGREG; i++)
+ prgregset[i] = core_gregs[i];
+
+ supply_gregset (&prgregset);
+ }
+#endif /* HAVE_PRGREGSET32_T */
else if (core_reg_size == sizeof (struct regs))
{
-#define gregs ((struct regs *)core_reg_sect)
+ struct regs *gregs = (struct regs *) core_reg_sect;
+
/* G0 *always* holds 0. */
*(int *) &registers[REGISTER_BYTE (0)] = 0;
@@ -103,14 +128,41 @@ fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
}
else if (which == 2)
{
- if (core_reg_size == sizeof (prfpregset))
+ prfpregset_t prfpregset;
+
+ if (core_reg_size == sizeof (prfpregset_t))
{
memcpy ((char *) &prfpregset, core_reg_sect, sizeof (prfpregset));
supply_fpregset (&prfpregset);
}
+#if defined (HAVE_PRFPREGSET32_T)
+ /* 32-bit corefile, 64-bit debugger. */
+ else if (core_reg_size == sizeof (prfpregset32_t))
+ {
+ prfpregset32_t *core_fpregset;
+
+ /* Can't use memcpy here, because the core file contains
+ 32-bit regs; supply_fpregset expects 64-bit regs. */
+
+ core_fpregset = (prfpregset32_t *) core_reg_sect;
+ for (i = 0; i < 16; i++)
+ prfpregset.pr_fr.pr_dregs[i] = core_fpregset->pr_fr.pr_dregs[i];
+ while (i < 32)
+ prfpregset.pr_fr.pr_dregs[i++] = 0;
+
+ prfpregset.pr_fsr = core_fpregset->pr_fsr;
+ prfpregset.pr_qcnt = core_fpregset->pr_qcnt;
+ prfpregset.pr_q_entrysize = core_fpregset->pr_q_entrysize;
+ prfpregset.pr_en = core_fpregset->pr_en;
+ /* We will not use the pr_q array. */
+
+ supply_fpregset (&prfpregset);
+ }
+#endif /* HAVE_PRFPREGSET32_T */
else if (core_reg_size >= sizeof (struct fpu))
{
-#define fpuregs ((struct fpu *) core_reg_sect)
+ struct fpu *fpuregs = (struct fpu *) core_reg_sect;
+
memcpy (&registers[REGISTER_BYTE (FP0_REGNUM)], &fpuregs->fpu_fr,
sizeof (fpuregs->fpu_fr));
memcpy (&registers[REGISTER_BYTE (FPS_REGNUM)], &fpuregs->fpu_fsr,
diff --git a/gdb/sol-thread.c b/gdb/sol-thread.c
index 0ddeb26..3e5014e 100644
--- a/gdb/sol-thread.c
+++ b/gdb/sol-thread.c
@@ -1,5 +1,5 @@
/* Low level interface for debugging Solaris threads for GDB, the GNU debugger.
- Copyright 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
This file is part of GDB.
@@ -57,6 +57,7 @@
#include <sys/stat.h>
#include <dlfcn.h>
#include "gdbcmd.h"
+#include "gdbcore.h"
extern struct target_ops sol_thread_ops; /* Forward declaration */
extern struct target_ops sol_core_ops; /* Forward declaration */
@@ -1044,6 +1045,13 @@ rw_common (int dowrite, const struct ps_prochandle *ph, gdb_ps_addr_t addr,
inferior_pid = procfs_first_available (); /* Find any live lwp. */
/* Note: don't need to call switch_to_thread; we're just reading memory. */
+#if defined (__sparcv9)
+ /* For Sparc64 cross Sparc32, make sure the address has not been
+ accidentally sign-extended (or whatever) to beyond 32 bits. */
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ addr &= 0xffffffff;
+#endif
+
while (size > 0)
{
int cc;
@@ -1301,6 +1309,25 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
return PS_OK;
}
+/* Identify process as 32-bit or 64-bit.
+ At the moment I'm using bfd to do this.
+ There might be a more solaris-specific (eg. procfs) method,
+ but this ought to work. */
+
+ps_err_e
+ps_pdmodel (gdb_ps_prochandle_t ph, int *data_model)
+{
+ if (exec_bfd == 0)
+ return PS_ERR;
+
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ *data_model = PR_MODEL_ILP32;
+ else
+ *data_model = PR_MODEL_LP64;
+
+ return PS_OK;
+}
+
#ifdef TM_I386SOL2_H
/* Reads the local descriptor table of a LWP. */
diff --git a/gdb/solib.c b/gdb/solib.c
index d83c95a..1a725a5 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -19,7 +19,7 @@
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
+#define _SYSCALL32 /* for Sparc64 cross Sparc32 */
#include "defs.h"
/* This file is only compilable if link.h is available. */
@@ -107,24 +107,33 @@ static char *main_name_list[] =
NULL
};
-/* local data declarations */
-
-/* Macro to extract an address from a solib structure.
+/* Function to extract an address from a solib structure.
When GDB is configured for some 32-bit targets (e.g. Solaris 2.7
sparc), BFD is configured to handle 64-bit targets, so CORE_ADDR is
64 bits. We have to extract only the significant bits of addresses
- to get the right address when accessing the core file BFD. */
+ to get the right address when accessing the core file BFD.
-#define SOLIB_EXTRACT_ADDRESS(member) \
- extract_address (&member, sizeof (member))
+ We'll use the BFD itself to determine the number of significant bits.
+ MVS, June 2000 */
+
+static CORE_ADDR
+solib_extract_address (void *memberp)
+{
+ return extract_address (memberp,
+ bfd_elf_get_arch_size (exec_bfd) / 8);
+}
+
+#define SOLIB_EXTRACT_ADDRESS(MEMBER) \
+ solib_extract_address (&MEMBER)
+
+/* local data declarations */
#ifndef SVR4_SHARED_LIBS
-#define LM_ADDR(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.lm_addr))
-#define LM_NEXT(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.lm_next))
-#define LM_NAME(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.lm_name))
-/* Test for first link map entry; first entry is a shared library. */
-#define IGNORE_FIRST_LINK_MAP_ENTRY(so) (0)
+/* NOTE: converted the macros LM_ADDR, LM_NEXT, LM_NAME and
+ IGNORE_FIRST_LINK_MAP_ENTRY into functions (see below).
+ MVS, June 2000 */
+
static struct link_dynamic dynamic_copy;
static struct link_dynamic_2 ld_2_copy;
static struct ld_debug debug_copy;
@@ -133,13 +142,11 @@ static CORE_ADDR flag_addr;
#else /* SVR4_SHARED_LIBS */
-#define LM_ADDR(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.l_addr))
-#define LM_NEXT(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.l_next))
-#define LM_NAME(so) (SOLIB_EXTRACT_ADDRESS ((so) -> lm.l_name))
-/* Test for first link map entry; first entry is the exec-file. */
-#define IGNORE_FIRST_LINK_MAP_ENTRY(so) \
- (SOLIB_EXTRACT_ADDRESS ((so) -> lm.l_prev) == 0)
static struct r_debug debug_copy;
+#if defined (HAVE_STRUCT_LINK_MAP32)
+static struct r_debug32 debug32_copy; /* Sparc64 cross Sparc32 */
+#endif
+
char shadow_contents[BREAKPOINT_MAX]; /* Stash old bkpt addr contents */
#endif /* !SVR4_SHARED_LIBS */
@@ -152,6 +159,9 @@ struct so_list
struct so_list *next; /* next structure in linked list */
struct link_map lm; /* copy of link map from inferior */
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ struct link_map32 lm32; /* copy of link map from 32-bit inferior */
+#endif
CORE_ADDR lmaddr; /* addr in inferior lm was read from */
/* Shared object file name, exactly as it appears in the
@@ -179,6 +189,107 @@ struct so_list
};
static struct so_list *so_list_head; /* List of known shared objects */
+
+/* link map access functions */
+
+#ifndef SVR4_SHARED_LIBS
+
+static CORE_ADDR
+LM_ADDR (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.lm_addr, sizeof (so->lm32.lm_addr));
+ else
+#endif
+ return extract_address (&so->lm.lm_addr, sizeof (so->lm.lm_addr));
+}
+
+static CORE_ADDR
+LM_NEXT (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.lm_next, sizeof (so->lm32.lm_next));
+ else
+#endif
+ return extract_address (&so->lm.lm_next, sizeof (so->lm.lm_next));
+}
+
+static CORE_ADDR
+LM_NAME (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.lm_name, sizeof (so->lm32.lm_name));
+ else
+#endif
+ return extract_address (&so->lm.lm_name, sizeof (so->lm.lm_name));
+}
+
+static int
+IGNORE_FIRST_LINK_MAP_ENTRY (so)
+ struct so_list *so;
+{
+ return 0;
+}
+
+#else /* SVR4_SHARED_LIBS */
+
+static CORE_ADDR
+LM_ADDR (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.l_addr, sizeof (so->lm32.l_addr));
+ else
+#endif
+ return extract_address (&so->lm.l_addr, sizeof (so->lm.l_addr));
+}
+
+static CORE_ADDR
+LM_NEXT (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.l_next, sizeof (so->lm32.l_next));
+ else
+#endif
+ return extract_address (&so->lm.l_next, sizeof (so->lm.l_next));
+}
+
+static CORE_ADDR
+LM_NAME (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return extract_address (&so->lm32.l_name, sizeof (so->lm32.l_name));
+ else
+#endif
+ return extract_address (&so->lm.l_name, sizeof (so->lm.l_name));
+}
+
+static int
+IGNORE_FIRST_LINK_MAP_ENTRY (so)
+ struct so_list *so;
+{
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ return (solib_extract_address (&(so) -> lm32.l_prev) == 0);
+ else
+#endif
+ return (solib_extract_address (&(so) -> lm.l_prev) == 0);
+}
+
+#endif /* !SVR4_SHARED_LIBS */
+
+
static CORE_ADDR debug_base; /* Base of dynamic linker structures */
static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */
@@ -925,12 +1036,23 @@ first_link_map_member (void)
}
#else /* SVR4_SHARED_LIBS */
-
- read_memory (debug_base, (char *) &debug_copy, sizeof (struct r_debug));
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ {
+ read_memory (debug_base, (char *) &debug32_copy,
+ sizeof (struct r_debug32));
+ lm = SOLIB_EXTRACT_ADDRESS (debug32_copy.r_map);
+ }
+ else
+#endif
+ {
+ read_memory (debug_base, (char *) &debug_copy,
+ sizeof (struct r_debug));
+ lm = SOLIB_EXTRACT_ADDRESS (debug_copy.r_map);
+ }
/* FIXME: Perhaps we should validate the info somehow, perhaps by
checking r_version for a known version number, or r_state for
RT_CONSISTENT. */
- lm = SOLIB_EXTRACT_ADDRESS (debug_copy.r_map);
#endif /* !SVR4_SHARED_LIBS */
@@ -962,7 +1084,6 @@ open_symbol_file_object (from_ttyp)
int *from_ttyp; /* sneak past catch_errors */
{
CORE_ADDR lm;
- struct link_map lmcopy;
char *filename;
int errcode;
@@ -977,15 +1098,35 @@ open_symbol_file_object (from_ttyp)
if ((lm = first_link_map_member ()) == 0)
return 0; /* failed somehow... */
- /* Read from target memory to GDB. */
- read_memory (lm, (void *) &lmcopy, sizeof (lmcopy));
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ {
+ struct link_map32 lmcopy;
+ /* Read from target memory to GDB. */
+ read_memory (lm, (void *) &lmcopy, sizeof (lmcopy));
- if (lmcopy.l_name == 0)
- return 0; /* no filename. */
+ if (lmcopy.l_name == 0)
+ return 0; /* no filename. */
+
+ /* Now fetch the filename from target memory. */
+ target_read_string (SOLIB_EXTRACT_ADDRESS (lmcopy.l_name),
+ &filename, MAX_PATH_SIZE - 1, &errcode);
+ }
+ else
+#endif /* HAVE_STRUCT_LINK_MAP32 */
+ {
+ struct link_map lmcopy;
+ /* Read from target memory to GDB. */
+ read_memory (lm, (void *) &lmcopy, sizeof (lmcopy));
+
+ if (lmcopy.l_name == 0)
+ return 0; /* no filename. */
+
+ /* Now fetch the filename from target memory. */
+ target_read_string (SOLIB_EXTRACT_ADDRESS (lmcopy.l_name), &filename,
+ MAX_PATH_SIZE - 1, &errcode);
+ }
- /* Now fetch the filename from target memory. */
- target_read_string (SOLIB_EXTRACT_ADDRESS (lmcopy.l_name), &filename,
- MAX_PATH_SIZE - 1, &errcode);
if (errcode)
{
warning ("failed to read exec filename from attached file: %s",
@@ -1114,7 +1255,13 @@ current_sos (void)
memset (new, 0, sizeof (*new));
new->lmaddr = lm;
- read_memory (lm, (char *) &(new->lm), sizeof (struct link_map));
+
+#if defined (HAVE_STRUCT_LINK_MAP32)
+ if (bfd_elf_get_arch_size (exec_bfd) == 32)
+ read_memory (lm, (char *) &(new->lm32), sizeof (struct link_map32));
+ else
+#endif
+ read_memory (lm, (char *) &(new->lm), sizeof (struct link_map));
lm = LM_NEXT (new);
diff --git a/gdb/valops.c b/gdb/valops.c
index 19482f1..8a7f036 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -286,8 +286,8 @@ value_cast (struct type *type, register value_ptr arg2)
(LONGEST) (longest ? 1 : 0) : longest);
}
else if (code1 == TYPE_CODE_PTR && (code2 == TYPE_CODE_INT ||
- code2 == TYPE_CODE_ENUM ||
- code2 == TYPE_CODE_RANGE))
+ code2 == TYPE_CODE_ENUM ||
+ code2 == TYPE_CODE_RANGE))
{
int ptr_bit = HOST_CHAR_BIT * TYPE_LENGTH (type);
LONGEST longest = value_as_long (arg2);