From c5394b80aefdea6b2f589723a4b79bcbc1942629 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 18 Jan 2000 00:55:13 +0000 Subject: [PATCH] import gdb-2000-01-17 snapshot --- gdb/ChangeLog | 79 +++ gdb/Makefile.in | 2 +- gdb/config/sparc/tm-sun4sol2.h | 2 +- gdb/configure | 34 +- gdb/configure.in | 8 +- gdb/doc/ChangeLog | 6 + gdb/doc/gdb.texinfo | 22 +- gdb/event-top.c | 2 +- gdb/frame.h | 16 +- gdb/i386-linux-nat.c | 2 +- gdb/infrun.c | 16 +- gdb/rdi-share/ardi.c | 9 +- gdb/rdi-share/serdrv.c | 4 +- gdb/remote-rdi.c | 2 +- gdb/stack.c | 253 +++++---- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.base/default.exp | 2 +- gdb/testsuite/gdb.base/help.exp | 2 +- gdb/thread.c | 28 +- gdb/uw-thread.c | 1095 ++++++++++++++++++++++++++++++++++++ gdb/v850-tdep.c | 1 + sim/mcore/ChangeLog | 5 + sim/mcore/interp.c | 15 +- 23 files changed, 1441 insertions(+), 169 deletions(-) create mode 100644 gdb/uw-thread.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ccd1112..dd46c82 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,82 @@ +2000-01-17 Jason Molenda (jsm@bugshack.cygnus.com) + + * configure.in (NEW_PROC_API): Fix Unixware-matching regexp. + Fix from Robert Lipe . + * configure: Regenerated. + +2000-01-17 Elena Zannoni + + * stack.c (print_frame_info_base): Break up into the frame info + (location) printing part and the rest (source line printing). + (print_frame): New function. Take care of printing the location + information. + Update copyright. + + * infrun.c (normal_stop): Use enum values rather than integers for the + source_flag to be passed to show_and_print_stack_frame(). + Update copyright. + + * frame.h (print_what): New enum for 'source' argument to + print_frame_info_base(). Use this instead of obscure numbers. + Update copyright. + +Sun Jan 16 17:58:00 2000 David Taylor + + * event-top.c (stdin_event_handler): call quit_command rather than + exit -- run cleanups, give target code a chance to say goodbye to + the target. Fixes bug where the inferior processes were left + around on Solaris (and probably elsewhere) by the testsuite. + +2000-01-14 Mark Salter + + * v850-tdep.c (v850_target_architecture_hook): Setup correct + machine id for disassembly. + +Thu Jan 13 23:34:17 EST 2000 Nicholas Duffek + + * uw-thread.c: Document libthread.so debugging interface. Minor + comment and formatting tweaks. + (DEBUG): #define as 0 instead of 1. + (CALL_BASE): Include function name in error msg. + (libthread_stub): Adjust inferior_pid after thread exit. + (uw_thread_create_inferior): Deactivate uw_thread_ops before + asking procfs_ops to create inferior. + (libthread_init): Don't return nonlocally on error. + +2000-01-12 Fernando Nasser + + * rdi-share/ardi.c (negotiate_params): Fix initialization of static + variable. + +2000-01-12 Fernando Nasser + + * remote-rdi.c (arm_rdi_open): Call arm-rdi-close() to make sure + both sides are on the same state. + +2000-01-12 Fernando Nasser + + * rdi-share/serdrv.c (find_baud_rate): Fix entries for 57600 and + 115200 (minor syntax mistake). + +2000-01-12 Jim Blandy + + * config/sparc/tm-sun4sol2.h (MERGEPID): Provide a definition for + this here, to go along with the definitions of PIDGET and TIDGET. + +2000-01-12 Elena Zannoni + + * thread.c (do_captured_thread_select): New function. Switch + current thread, safely from within catch_errors(). + (gdb_thread_select): New function. Switch threads safely. + (thread_command): Use gdb_thread_select(). + +2000-01-11 Christopher Faylor + + * configure.in: Avoid linking -limagehlp unless it's a native build. + * configure: Regenerate. + * thread.cc (add_thread): Clear private data pointer here or suffer + strange behavior when it is checked for NULL later. + 2000-01-09 Christopher Faylor * win32nat.c (handle_exceptions): Handle various arithmetic exceptions. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 76574a5..8ce6044 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -229,7 +229,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \ ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES) -VERSION = 20000110 +VERSION = 20000117 DIST=gdb LINT=/usr/5bin/lint diff --git a/gdb/config/sparc/tm-sun4sol2.h b/gdb/config/sparc/tm-sun4sol2.h index cc3abfc..e348f79 100644 --- a/gdb/config/sparc/tm-sun4sol2.h +++ b/gdb/config/sparc/tm-sun4sol2.h @@ -78,4 +78,4 @@ extern char *sunpro_static_transform_name PARAMS ((char *)); /* Macros to extract process id and thread id from a composite pid/tid */ #define PIDGET(pid) ((pid) & 0xffff) #define TIDGET(pid) (((pid) >> 16) & 0xffff) - +#define MERGEPID(pid, tid) (((tid) << 16) | (pid)) diff --git a/gdb/configure b/gdb/configure index 4d76095..6e456d7 100755 --- a/gdb/configure +++ b/gdb/configure @@ -4181,7 +4181,7 @@ EOF EOF ;; - *-*-unixware* | *-*-sysv4.2uw2.* | *-*-sysv4.2uw7.*) + *-*-unixware* | *-*-sysv4.2* | *-*-sysv5*) cat >> confdefs.h <<\EOF #define NEW_PROC_API 1 EOF @@ -5546,7 +5546,11 @@ fi # libreadline needs libuser32.a in a cygwin environment WIN32LIBS= if test x$gdb_cv_os_cygwin = xyes; then - WIN32LIBS="-luser32 -limagehlp" + WIN32LIBS="-luser32" + case "${target}" in + *cygwin*) WIN32LIBS="$WIN32LIBS -limagehlp" + ;; + esac fi @@ -5556,7 +5560,7 @@ fi # Uses ac_ vars as temps to allow command line to override cache and checks. # --without-x overrides everything else, but does not touch the cache. echo $ac_n "checking for X""... $ac_c" 1>&6 -echo "configure:6767: checking for X" >&5 +echo "configure:6771: checking for X" >&5 # Check whether --with-x or --without-x was given. if test "${with_x+set}" = set; then @@ -5618,12 +5622,12 @@ if test "$ac_x_includes" = NO; then # First, try using that file with no special directory specified. cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:6834: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:6838: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -5692,14 +5696,14 @@ if test "$ac_x_libraries" = NO; then ac_save_LIBS="$LIBS" LIBS="-l$x_direct_test_library $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:6914: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* LIBS="$ac_save_LIBS" # We can link X programs with no special library path. @@ -5979,12 +5983,12 @@ fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:7261: checking for Cygwin environment" >&5 +echo "configure:7265: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:7281: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -6012,19 +6016,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:7294: checking for mingw32 environment" >&5 +echo "configure:7298: checking for mingw32 environment" >&5 if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:7310: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -6043,7 +6047,7 @@ test "$ac_cv_mingw32" = yes && MINGW32=yes echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:7325: checking for executable suffix" >&5 +echo "configure:7329: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -6053,7 +6057,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:7335: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:7339: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; diff --git a/gdb/configure.in b/gdb/configure.in index d967116..e8d6c3b 100644 --- a/gdb/configure.in +++ b/gdb/configure.in @@ -152,7 +152,7 @@ if test "${target}" = "${host}"; then AC_DEFINE(START_INFERIOR_TRAPS_EXPECTED,2) AC_DEFINE(sys_quotactl) ;; - *-*-unixware* | *-*-sysv4.2uw2.* | *-*-sysv4.2uw7.*) + *-*-unixware* | *-*-sysv4.2* | *-*-sysv5*) AC_DEFINE(NEW_PROC_API) ;; # FIXME: we would like to define NEW_PROC_API for all versions of @@ -488,7 +488,11 @@ AC_SUBST(TERM_LIB) # libreadline needs libuser32.a in a cygwin environment WIN32LIBS= if test x$gdb_cv_os_cygwin = xyes; then - WIN32LIBS="-luser32 -limagehlp" + WIN32LIBS="-luser32" + case "${target}" in + *cygwin*) WIN32LIBS="$WIN32LIBS -limagehlp" + ;; + esac fi AC_SUBST(WIN32LIBS) diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 30bef42..d6aedaa 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,9 @@ +2000-01-16 Tom Tromey + + * gdb.texinfo (Breakpoints): Mention breakpoint ranges. + (Delete Breaks): Mention range arguments. + (Disabling): Likewise. + 2000-01-05 Dmitry Sivachenko * gdb.texinfo: Wrap "ASCII" in @sc{}; clarify a few sentences. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0f34d26..63f3355 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -2100,6 +2100,14 @@ breakpoint you want to change. Each breakpoint may be @dfn{enabled} or @dfn{disabled}; if disabled, it has no effect on your program until you enable it again. +@cindex breakpoint ranges +@cindex ranges of breakpoints +Some @value{GDBN} commands accept a range of breakpoints on which to +operate. A breakpoint range is either a single breakpoint number, like +@samp{5}, or two such numbers, in increasing order, separated by a +hyphen, like @samp{5-7}. When a breakpoint range is given to a command, +all breakpoint in that range are operated on. + @menu * Set Breaks:: Setting breakpoints * Set Watchpoints:: Setting watchpoints @@ -2633,9 +2641,9 @@ Delete any breakpoints set at or within the code of the specified line. @cindex delete breakpoints @kindex delete @kindex d -@item delete @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} -Delete the breakpoints, watchpoints, or catchpoints of the numbers -specified as arguments. If no argument is specified, delete all +@item delete @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} +Delete the breakpoints, watchpoints, or catchpoints of the breakpoint +ranges specified as arguments. If no argument is specified, delete all breakpoints (@value{GDBN} asks confirmation, unless you have @code{set confirm off}). You can abbreviate this command as @code{d}. @end table @@ -2681,7 +2689,7 @@ watchpoints, and catchpoints: @kindex disable breakpoints @kindex disable @kindex dis -@item disable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@item disable @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} Disable the specified breakpoints---or all breakpoints, if none are listed. A disabled breakpoint has no effect but is not forgotten. All options such as ignore-counts, conditions and commands are remembered in @@ -2690,15 +2698,15 @@ case the breakpoint is enabled again later. You may abbreviate @kindex enable breakpoints @kindex enable -@item enable @r{[}breakpoints@r{]} @r{[}@var{bnums}@dots{}@r{]} +@item enable @r{[}breakpoints@r{]} @r{[}@var{range}@dots{}@r{]} Enable the specified breakpoints (or all defined breakpoints). They become effective once again in stopping your program. -@item enable @r{[}breakpoints@r{]} once @var{bnums}@dots{} +@item enable @r{[}breakpoints@r{]} once @var{range}@dots{} Enable the specified breakpoints temporarily. @value{GDBN} disables any of these breakpoints immediately after stopping your program. -@item enable @r{[}breakpoints@r{]} delete @var{bnums}@dots{} +@item enable @r{[}breakpoints@r{]} delete @var{range}@dots{} Enable the specified breakpoints to work once, then die. @value{GDBN} deletes any of these breakpoints as soon as your program stops there. @end table diff --git a/gdb/event-top.c b/gdb/event-top.c index cac4922..3d21a1a 100644 --- a/gdb/event-top.c +++ b/gdb/event-top.c @@ -410,7 +410,7 @@ stdin_event_handler (int error, gdb_client_data client_data) delete_file_handler (input_fd); discard_all_continuations (); /* If stdin died, we may as well kill gdb. */ - exit (1); + quit_command ((char *) 0, stdin == instream); } else (*call_readline) (client_data); diff --git a/gdb/frame.h b/gdb/frame.h index ad329c5..0912205 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -1,5 +1,5 @@ /* Definitions for dealing with stack frames, for GDB, the GNU debugger. - Copyright 1986, 1989, 1991, 1992, 1999 Free Software Foundation, Inc. + Copyright 1986, 1989, 1991, 1992, 1999, 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -99,6 +99,20 @@ struct frame_info struct frame_info *next, *prev; }; +/* Values for the source flag to be used in print_frame_info_base(). */ +enum print_what + { + /* Print only the source line, like in stepi. */ + SRC_LINE = -1, + /* Print only the location, i.e. level, address (sometimes) + function, args, file, line, line num. */ + LOCATION, + /* Print both of the above. */ + SRC_AND_LOC, + /* Print location only, but always include the address. */ + LOC_AND_ADDRESS + }; + /* Allocate additional space for appendices to a struct frame_info. */ #ifndef SIZEOF_FRAME_SAVED_REGS diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 2b350f0..dddb218 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -146,7 +146,7 @@ fill_gregset (gregset_t *gregsetp, signed char valid[NUM_GREGS]; memset (valid, 0, sizeof (valid)); valid[regno] = 1; - convert_to_gregset (gregsetp, valid, valid); + convert_to_gregset (gregsetp, registers, valid); } } diff --git a/gdb/infrun.c b/gdb/infrun.c index be1e6c7..549c515 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1,5 +1,5 @@ /* Target-struct-independent code to start (run) and stop an inferior process. - Copyright 1986-1989, 1991-1999 Free Software Foundation, Inc. + Copyright 1986-1989, 1991-2000 Free Software Foundation, Inc. This file is part of GDB. @@ -3381,15 +3381,15 @@ The same program may be running in another process.\n"); if (stop_step && step_frame_address == FRAME_FP (get_current_frame ()) && step_start_function == find_pc_function (stop_pc)) - source_flag = -1; /* finished step, just print source line */ + source_flag = SRC_LINE; /* finished step, just print source line */ else - source_flag = 1; /* print location and source line */ + source_flag = SRC_AND_LOC; /* print location and source line */ break; case PRINT_SRC_AND_LOC: - source_flag = 1; /* print location and source line */ + source_flag = SRC_AND_LOC; /* print location and source line */ break; case PRINT_SRC_ONLY: - source_flag = -1; + source_flag = SRC_LINE; break; case PRINT_NOTHING: do_frame_printing = 0; @@ -3400,9 +3400,9 @@ The same program may be running in another process.\n"); /* The behavior of this routine with respect to the source flag is: - -1: Print only source line - 0: Print only location - 1: Print location and source line */ + SRC_LINE: Print only source line + LOCATION: Print only location + SRC_AND_LOC: Print location and source line */ if (do_frame_printing) show_and_print_stack_frame (selected_frame, -1, source_flag); diff --git a/gdb/rdi-share/ardi.c b/gdb/rdi-share/ardi.c index d1dc191..43b8cf4 100644 --- a/gdb/rdi-share/ardi.c +++ b/gdb/rdi-share/ardi.c @@ -320,9 +320,12 @@ static AdpErrs negotiate_params( const ParameterOptions *user_options ) time_t t; - static volatile NegotiateState n_state = { - FALSE, FALSE, FALSE, &accepted_config }; - + static volatile NegotiateState n_state; + n_state.negotiate_resp = FALSE; + n_state.negotiate_ack = FALSE; + n_state.link_check_resp = FALSE; + n_state.accepted_config = &accepted_config; + #ifdef DEBUG angel_DebugPrint( "negotiate_params\n" ); #endif diff --git a/gdb/rdi-share/serdrv.c b/gdb/rdi-share/serdrv.c index 9a2992e..91f8f19 100644 --- a/gdb/rdi-share/serdrv.c +++ b/gdb/rdi-share/serdrv.c @@ -85,10 +85,10 @@ static struct writestate wstate; * The set of parameter options supported by the device */ static unsigned int baud_options[] = { -#ifdef B115200 || __hpux +#if defined(B115200) || defined(__hpux) 115200, #endif -#ifdef B57600 || __hpux +#if defined(B57600) || defined(__hpux) 57600, #endif 38400, 19200, 9600 diff --git a/gdb/remote-rdi.c b/gdb/remote-rdi.c index 01433c8..63c8d60 100644 --- a/gdb/remote-rdi.c +++ b/gdb/remote-rdi.c @@ -251,7 +251,7 @@ device is attached to the remote system (e.g. /dev/ttya)."); /* Make the basic low-level connection. */ - Adp_CloseDevice (); + arm_rdi_close (0); rslt = Adp_OpenDevice (devName, openArgs, rdi_heartbeat); if (rslt != adp_ok) diff --git a/gdb/stack.c b/gdb/stack.c index 52a7d99..d344bab 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1,5 +1,5 @@ /* Print and select stack frames for GDB, the GNU debugger. - Copyright 1986, 87, 89, 91, 92, 93, 94, 95, 96, 98, 1999 + Copyright 1986, 87, 89, 91, 92, 93, 94, 95, 96, 98, 1999, 2000 Free Software Foundation, Inc. This file is part of GDB. @@ -92,6 +92,12 @@ static int print_block_frame_locals PARAMS ((struct block *, int, GDB_FILE *)); +static void print_frame (struct frame_info *fi, + int level, + int source, + int args, + struct symtab_and_line sal); + static void print_frame_info_base PARAMS ((struct frame_info *, int, int, int)); static void print_stack_frame_base PARAMS ((struct frame_info *, int, int)); @@ -328,14 +334,14 @@ print_args_stub (args) } /* Print information about a frame for frame "fi" at level "level". - * Used in "where" output, also used to emit breakpoint or step messages. - * LEVEL is the level of the frame, or -1 if it is the innermost frame - * but we don't want to print the level. - * The meaning of the SOURCE argument is: - * -1: Print only source line - * 0: Print only location - * 1: Print location and source line - */ + Used in "where" output, also used to emit breakpoint or step + messages. + LEVEL is the level of the frame, or -1 if it is the + innermost frame but we don't want to print the level. + The meaning of the SOURCE argument is: + SRC_LINE: Print only source line + LOCATION: Print only location + LOC_AND_SRC: Print location and source line. */ static void print_frame_info_base (fi, level, source, args) @@ -345,9 +351,8 @@ print_frame_info_base (fi, level, source, args) int args; { struct symtab_and_line sal; - struct symbol *func; - register char *funname = 0; - enum language funlang = language_unknown; + int source_print; + int location_print; #if 0 char buf[MAX_REGISTER_RAW_SIZE]; @@ -406,6 +411,57 @@ print_frame_info_base (fi, level, source, args) && !fi->next->signal_handler_caller && !frame_in_dummy (fi->next)); + location_print = (source == LOCATION + || source == LOC_AND_ADDRESS + || source == SRC_AND_LOC); + + if (location_print || !sal.symtab) + print_frame (fi, level, source, args, sal); + + source_print = (source == SRC_LINE || source == SRC_AND_LOC); + + if (source_print && sal.symtab) + { + int done = 0; + int mid_statement = (source == SRC_LINE) && (fi->pc != sal.pc); + + if (annotation_level) + done = identify_source_line (sal.symtab, sal.line, mid_statement, + fi->pc); + if (!done) + { + if (addressprint && mid_statement && !tui_version) + { + print_address_numeric (fi->pc, 1, gdb_stdout); + printf_filtered ("\t"); + } + if (print_frame_info_listing_hook) + print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0); + else if (!tui_version) + print_source_lines (sal.symtab, sal.line, sal.line + 1, 0); + } + current_source_line = max (sal.line - lines_to_list / 2, 1); + } + + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + annotate_frame_end (); + + gdb_flush (gdb_stdout); +} + +static void +print_frame (struct frame_info *fi, + int level, + int source, + int args, + struct symtab_and_line sal) +{ + struct symbol *func; + register char *funname = 0; + enum language funlang = language_unknown; + func = find_pc_function (fi->pc); if (func) { @@ -446,19 +502,17 @@ print_frame_info_base (fi, level, source, args) } else { - /* I'd like to use SYMBOL_SOURCE_NAME() here, to display - * the demangled name that we already have stored in - * the symbol table, but we stored a version with - * DMGL_PARAMS turned on, and here we don't want - * to display parameters. So call the demangler again, - * with DMGL_ANSI only. RT - * (Yes, I know that printf_symbol_filtered() will - * again try to demangle the name on the fly, but - * the issue is that if cplus_demangle() fails here, - * it'll fail there too. So we want to catch the failure - * ("demangled==NULL" case below) here, while we still - * have our hands on the function symbol.) - */ + /* I'd like to use SYMBOL_SOURCE_NAME() here, to display the + demangled name that we already have stored in the symbol + table, but we stored a version with DMGL_PARAMS turned + on, and here we don't want to display parameters. So call + the demangler again, with DMGL_ANSI only. (Yes, I know + that printf_symbol_filtered() will again try to demangle + the name on the fly, but the issue is that if + cplus_demangle() fails here, it'll fail there too. So we + want to catch the failure ("demangled==NULL" case below) + here, while we still have our hands on the function + symbol.) */ char *demangled; funname = SYMBOL_NAME (func); funlang = SYMBOL_LANGUAGE (func); @@ -466,10 +520,9 @@ print_frame_info_base (fi, level, source, args) { demangled = cplus_demangle (funname, DMGL_ANSI); if (demangled == NULL) - /* If the demangler fails, try the demangled name - * from the symbol table. This'll have parameters, - * but that's preferable to diplaying a mangled name. - */ + /* If the demangler fails, try the demangled name from + the symbol table. This'll have parameters, but + that's preferable to diplaying a mangled name. */ funname = SYMBOL_SOURCE_NAME (func); } } @@ -484,104 +537,76 @@ print_frame_info_base (fi, level, source, args) } } - if (source >= 0 || !sal.symtab) - { - annotate_frame_begin (level == -1 ? 0 : level, fi->pc); + annotate_frame_begin (level == -1 ? 0 : level, fi->pc); - if (level >= 0) - printf_filtered ("#%-2d ", level); - if (addressprint) - if (fi->pc != sal.pc || !sal.symtab) - { - annotate_frame_address (); - print_address_numeric (fi->pc, 1, gdb_stdout); - annotate_frame_address_end (); - printf_filtered (" in "); - } - annotate_frame_function_name (); - fprintf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang, - DMGL_ANSI); + + if (level >= 0) + printf_filtered ("#%-2d ", level); + if (addressprint) + if (fi->pc != sal.pc || !sal.symtab || source == LOC_AND_ADDRESS) + { + annotate_frame_address (); + print_address_numeric (fi->pc, 1, gdb_stdout); + annotate_frame_address_end (); + printf_filtered (" in "); + } + annotate_frame_function_name (); + fprintf_symbol_filtered (gdb_stdout, funname ? funname : "??", funlang, + DMGL_ANSI); + wrap_here (" "); + annotate_frame_args (); + + fputs_filtered (" (", gdb_stdout); + if (args) + { + struct print_args_args args; + args.fi = fi; + args.func = func; + args.stream = gdb_stdout; + catch_errors (print_args_stub, &args, "", RETURN_MASK_ALL); + QUIT; + } + printf_filtered (")"); + if (sal.symtab && sal.symtab->filename) + { + annotate_frame_source_begin (); wrap_here (" "); - annotate_frame_args (); - fputs_filtered (" (", gdb_stdout); - if (args) - { - struct print_args_args args; - args.fi = fi; - args.func = func; - args.stream = gdb_stdout; - catch_errors (print_args_stub, &args, "", RETURN_MASK_ALL); - QUIT; - } - printf_filtered (")"); - if (sal.symtab && sal.symtab->filename) - { - annotate_frame_source_begin (); - wrap_here (" "); - printf_filtered (" at "); - annotate_frame_source_file (); - printf_filtered ("%s", sal.symtab->filename); - annotate_frame_source_file_end (); - printf_filtered (":"); - annotate_frame_source_line (); - printf_filtered ("%d", sal.line); - annotate_frame_source_end (); - } + printf_filtered (" at "); + annotate_frame_source_file (); + printf_filtered ("%s", sal.symtab->filename); + annotate_frame_source_file_end (); + printf_filtered (":"); + annotate_frame_source_line (); + printf_filtered ("%d", sal.line); + annotate_frame_source_end (); + } #ifdef PC_LOAD_SEGMENT - /* If we couldn't print out function name but if can figure out what + /* If we couldn't print out function name but if can figure out what load segment this pc value is from, at least print out some info about its load segment. */ - if (!funname) - { - annotate_frame_where (); - wrap_here (" "); - printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc)); - } -#endif -#ifdef PC_SOLIB - if (!funname || (!sal.symtab || !sal.symtab->filename)) - { - char *lib = PC_SOLIB (fi->pc); - if (lib) - { - annotate_frame_where (); - wrap_here (" "); - printf_filtered (" from %s", lib); - } - } -#endif - printf_filtered ("\n"); + if (!funname) + { + annotate_frame_where (); + wrap_here (" "); + printf_filtered (" from %s", PC_LOAD_SEGMENT (fi->pc)); } +#endif /* PC_LOAD_SEGMENT */ - if ((source != 0) && sal.symtab) +#ifdef PC_SOLIB + if (!funname || (!sal.symtab || !sal.symtab->filename)) { - int done = 0; - int mid_statement = source < 0 && fi->pc != sal.pc; - if (annotation_level) - done = identify_source_line (sal.symtab, sal.line, mid_statement, - fi->pc); - if (!done) + char *lib = PC_SOLIB (fi->pc); + if (lib) { - if (addressprint && mid_statement && !tui_version) - { - print_address_numeric (fi->pc, 1, gdb_stdout); - printf_filtered ("\t"); - } - if (print_frame_info_listing_hook) - print_frame_info_listing_hook (sal.symtab, sal.line, sal.line + 1, 0); - else if (!tui_version) - print_source_lines (sal.symtab, sal.line, sal.line + 1, 0); + annotate_frame_where (); + wrap_here (" "); + printf_filtered (" from %s", lib); } - current_source_line = max (sal.line - lines_to_list / 2, 1); } +#endif /* PC_SOLIB */ - if (source != 0) - set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); - - annotate_frame_end (); - - gdb_flush (gdb_stdout); + printf_filtered ("\n"); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 5d44af6..27c1004 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2000-01-17 Fernando Nasser + + * gdb.base/default.exp: Fix expected pattern. + * gdb.base/help.exp: Same. + 2000-01-10 Elena Zannoni * gdb.base/so-indr-cl.exp: Don't execute the test if not on HPUX. diff --git a/gdb/testsuite/gdb.base/default.exp b/gdb/testsuite/gdb.base/default.exp index 6d11eff..8fcfc51 100644 --- a/gdb/testsuite/gdb.base/default.exp +++ b/gdb/testsuite/gdb.base/default.exp @@ -727,7 +727,7 @@ gdb_expect { if ![istarget "*-*-udi*"] then { send_gdb "target remote\n" gdb_expect { - -re "To open a remote debug connection, you need to specify what.*serial.*device is attached to the remote system .e.g. .*$gdb_prompt $"\ + -re "To open a remote debug connection, you need to specify what.*serial.*device is attached to the remote system.*.e.g. .*$gdb_prompt $"\ { pass "target remote" } -re ".*A program is being debugged already. Kill it. .y or n.*$" { send_gdb "n\n" diff --git a/gdb/testsuite/gdb.base/help.exp b/gdb/testsuite/gdb.base/help.exp index 9c98c72..c78bd89 100644 --- a/gdb/testsuite/gdb.base/help.exp +++ b/gdb/testsuite/gdb.base/help.exp @@ -504,7 +504,7 @@ gdb_test "help target core" ".*Use a core file as a target.*Specify the filename # test help target exec gdb_test "help target exec" "Use an executable file as a target..*\[\r\n\]+Specify the filename of the executable file." "help target exec" # test help target remote -gdb_test "help target remote" "Use a remote computer via a serial line, using a gdb-specific protocol..*\[\r\n\]+Specify the serial device it is connected to .e.g. .*" "help target remote" +gdb_test "help target remote" "Use a remote computer via a serial line, using a gdb-specific protocol..*\[\r\n\]+Specify the serial device it is connected to.*\[\r\n\]+.e.g. .*" "help target remote" # test help target # the child process target may be "target child" or "target procfs" gdb_test "help target" "Connect to a target machine or process..*\[\r\n\]+The first argument is the type or protocol of the target machine..*\[\r\n\]+Remaining arguments are interpreted by the target protocol. For more.*\[\r\n\]+information on the arguments for a particular protocol, type.*\[\r\n\]+`help target ' followed by the protocol name..*\[\r\n\]+List of target subcommands:.*\[\r\n\]+target exec -- Use an executable file as a target.*\[\r\n\]+Type \"help target\" followed by target subcommand name for full documentation..*\[\r\n\]+Command name abbreviations are allowed if unambiguous." "help target" diff --git a/gdb/thread.c b/gdb/thread.c index f4b57af..0ef9a76 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -106,6 +106,7 @@ add_thread (pid) tp->stepping_through_solib_catchpoints = NULL; tp->stepping_through_sigtramp = 0; tp->next = thread_list; + tp->private = NULL; thread_list = tp; return tp; } @@ -602,9 +603,6 @@ thread_command (tidstr, from_tty) char *tidstr; int from_tty; { - int num; - struct thread_info *tp; - if (!tidstr) { /* Don't generate an error, just say which thread is current. */ @@ -621,7 +619,17 @@ thread_command (tidstr, from_tty) error ("No stack."); return; } - num = atoi (tidstr); + + gdb_thread_select (tidstr); +} + +static int +do_captured_thread_select (void *tidstr) +{ + int num; + struct thread_info *tp; + + num = atoi ((char *)tidstr); tp = find_thread_id (num); @@ -634,9 +642,6 @@ see the IDs of currently known threads.", num); switch_to_thread (tp->pid); - if (context_hook) - context_hook (num); - printf_filtered ("[Switching to thread %d (%s)]\n", pid_to_thread_id (inferior_pid), #if defined(HPUXHPPA) @@ -645,7 +650,16 @@ see the IDs of currently known threads.", num); target_pid_to_str (inferior_pid) #endif ); + print_stack_frame (selected_frame, selected_frame_level, 1); + return GDB_RC_OK; +} + +enum gdb_rc +gdb_thread_select (char *tidstr) +{ + return catch_errors (do_captured_thread_select, tidstr, + NULL, RETURN_MASK_ALL); } /* Commands with a prefix of `thread'. */ diff --git a/gdb/uw-thread.c b/gdb/uw-thread.c new file mode 100644 index 0000000..91d6638 --- /dev/null +++ b/gdb/uw-thread.c @@ -0,0 +1,1095 @@ +/* Low level interface for debugging UnixWare user-mode threads for + GDB, the GNU debugger. + + Copyright 1999, 2000 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +/* Like many systems, UnixWare implements two classes of threads: + kernel-mode threads, which are scheduled by the kernel; and + user-mode threads, which are scheduled by a library. UnixWare + calls these two classes lightweight processes (LWPs) and threads, + respectively. + + This module deals with user-mode threads. It calls procfs_ops + functions to deal with LWPs and processes and core_ops functions to + deal with core files. + + As of this writing, the user-mode thread debugging interface is not + documented beyond the comments in . The following + description has been gleaned from experience and from information + provided by SCO. + + libthread.so, against which all UnixWare user-mode thread programs + link, provides a global thread_debug structure named _thr_debug. + It has three fields: + + (1) thr_map is a pointer to a pointer to an element of a + thread_map ring. A thread_map contains a single thread's id + number, state, LWP pointer, recent register state, and other + useful information. + + (2) thr_brk is a pointer to a stub function that libthread.so + calls when it changes a thread's state, e.g. by creating it, + switching it to an LWP, or causing it to exit. + + (3) thr_debug_on controls whether libthread.so calls thr_brk(). + + Debuggers are able to track thread activity by setting a private + breakpoint on thr_brk() and setting thr_debug_on to 1. + + thr_brk() receives two arguments: + + (1) a pointer to a thread_map describing the thread being + changed; and + + (2) an enum thread_change specifying one of the following + changes: + + invalid unknown + thread_create thread has just been created + thread_exit thread has just exited + switch_begin thread will be switched to an LWP + switch_complete thread has been switched to an LWP + cancel_complete thread wasn't switched to an LWP + thread_suspend thread has been thr_suspend()ed + thread_suspend_pending thread will be thr_suspend()ed + thread_continue thread has been thr_continue()d + + The thread_map argument to thr_brk() is NULL under the following + circumstances: + + - The main thread is being acted upon. The main thread always + has id 1, so its thread_map is easy to find by scanning through + _thr_debug.thr_map. + + - A "switch_complete" change is occurring, which means that the + thread specified in the most recent "switch_begin" change has + moved to an LWP. + + - A "cancel_complete" change is occurring, which means that the + thread specified in the most recent "switch_begin" change has + not moved to an LWP after all. + + - A spurious "switch_begin" change is occurring after a + "thread_exit" change. + + Between switch_begin and switch_complete or cancel_complete, the + affected thread's LWP pointer is not reliable. It is possible that + other parts of the thread's thread_map are also unreliable during + that time. */ + + +#include "defs.h" +#include "gdbthread.h" +#include "target.h" +#include "inferior.h" +#include + +/* + * includes , which requires boolean_t from + * , which doesn't typedef boolean_t with gcc. + */ +#define boolean_t int +#include +#undef boolean_t + +#include /* for UnixWare 2.x */ + + +/* + * Whether to emit debugging output. + */ +#define DEBUG 0 + +/* + * Default debugging output file, overridden by envvar UWTHR_DEBUG. + */ +#define DEBUG_FILE "/dev/tty" + +/* + * #if DEBUG, write string S to the debugging output channel. + */ +#if !DEBUG +# define DBG(fmt_and_args) +# define DBG2(fmt_and_args) +#else +# define DBG(fmt_and_args) dbg fmt_and_args +# define DBG2(fmt_and_args) +#endif + +/* + * Back end to CALL_BASE() and TRY_BASE(): evaluate CALL, then convert + * inferior_pid to a composite thread/process id. + */ +#define CALL_BASE_1(call) \ +do { \ + DBG2(("CALL_BASE(" #call ")")); \ + call; \ + do_cleanups (infpid_cleanup); \ +} while (0) + +/* + * If inferior_pid can be converted to a composite lwp/process id, do so, + * evaluate base_ops function CALL, and then convert inferior_pid back to a + * composite thread/process id. + * + * Otherwise, issue an error message and return nonlocally. + */ +#define CALL_BASE(call) \ +do { \ + if (!lwp_infpid ()) \ + error ("uw-thread: "__FUNCTION__": no lwp"); \ + CALL_BASE_1 (call); \ +} while (0) + +/* + * Like CALL_BASE(), but instead of returning nonlocally on error, set + * *CALLED to whether the inferior_pid conversion was successful. + */ +#define TRY_BASE(call, called) \ +do { \ + if ((*(called) = lwp_infpid ())) \ + CALL_BASE_1 (call); \ +} while (0) + +/* + * Information passed by thread_iter() to its callback parameter. + */ +typedef struct { + struct thread_map map; + __lwp_desc_t lwp; + CORE_ADDR mapp; +} iter_t; + +/* + * Private thread data for the thread_info struct. + */ +struct private_thread_info { + int stable; /* 0 if libthread.so is modifying thread map */ + int thrid; /* thread id assigned by libthread.so */ + int lwpid; /* thread's lwp if .stable, 0 means no lwp */ + CORE_ADDR mapp; /* address of thread's map structure */ +}; + + +/* procfs.c's target-specific operations. */ +extern struct target_ops procfs_ops; + +/* Flag to prevent procfs.c from starting inferior processes. */ +extern int procfs_suppress_run; + +/* This module's target-specific operations. */ +static struct target_ops uw_thread_ops; + +/* Copy of the target over which uw_thread_ops is pushed. This is + more convenient than a pointer to procfs_ops or core_ops, because + they lack current_target's default callbacks. */ +static struct target_ops base_ops; + +/* Saved pointer to previous owner of target_new_objfile_hook. */ +static void (*target_new_objfile_chain)(struct objfile *); + +/* Whether we are debugging a user-space thread program. This isn't + set until after libthread.so is loaded by the program being + debugged. + + Except for module one-time intialization and where otherwise + documented, no functions in this module get called when + !uw_thread_active. */ +static int uw_thread_active; + +/* For efficiency, cache the addresses of libthread.so's _thr_debug + structure, its thr_brk stub function, and the main thread's map. */ +static CORE_ADDR thr_debug_addr; +static CORE_ADDR thr_brk_addr; +static CORE_ADDR thr_map_main; + +/* Remember the thread most recently marked as switching. Necessary because + libthread.so passes null map when calling stub with tc_*_complete. */ +static struct thread_info *switchto_thread; + +/* Cleanup chain for safely restoring inferior_pid after CALL_BASE. */ +static struct cleanup *infpid_cleanup; + + +#if DEBUG +/* + * Helper function for DBG() macro: if printf-style FMT is non-null, format it + * with args and display the result on the debugging output channel. + */ +static void +dbg (char *fmt, ...) +{ + static int fd = -1, len; + va_list args; + char buf[1024]; + char *path; + + if (!fmt) + return; + + if (fd < 0) + { + path = getenv ("UWTHR_DEBUG"); + if (!path) + path = DEBUG_FILE; + if ((fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, 0664)) < 0) + error ("can't open %s\n", path); + } + + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + + len = strlen (buf); + buf[len] = '\n'; + (void)write (fd, buf, len + 1); +} + +#if 0 +/* + * Return a string representing composite PID's components. + */ +static char * +dbgpid (int pid) +{ + static char *buf, buf1[80], buf2[80]; + if (!buf || buf == buf2) + buf = buf1; + else + buf = buf2; + + if (pid <= 0) + sprintf (buf, "%d", pid); + else + sprintf (buf, "%s %d/%d", ISTID (pid) ? "thr" : "lwp", + TIDGET (pid), PIDGET (pid)); + + return buf; +} + +/* + * Return a string representing thread state CHANGE. + */ +static char * +dbgchange (enum thread_change change) +{ + switch (change) { + case tc_invalid: return "invalid"; + case tc_thread_create: return "thread_create"; + case tc_thread_exit: return "thread_exit"; + case tc_switch_begin: return "switch_begin"; + case tc_switch_complete: return "switch_complete"; + case tc_cancel_complete: return "cancel_complete"; + case tc_thread_suspend: return "thread_suspend"; + case tc_thread_suspend_pending: return "thread_suspend_pending"; + case tc_thread_continue: return "thread_continue"; + default: return "unknown"; + } +} + +/* + * Return a string representing thread STATE. + */ +static char * +dbgstate (int state) +{ + switch (state) { + case TS_ONPROC: return "running"; + case TS_SLEEP: return "sleeping"; + case TS_RUNNABLE: return "runnable"; + case TS_ZOMBIE: return "zombie"; + case TS_SUSPENDED: return "suspended"; +#ifdef TS_FORK + case TS_FORK: return "forking"; +#endif + default: return "confused"; + } +} +#endif /* 0 */ +#endif /* DEBUG */ + + +/* + * Read the contents of _thr_debug into *DEBUGP. Return success. + */ +static int +read_thr_debug (struct thread_debug *debugp) +{ + return base_ops.to_xfer_memory (thr_debug_addr, (char *)debugp, + sizeof (*debugp), 0, &base_ops); +} + +/* + * Read into MAP the contents of the thread map at inferior process address + * MAPP. Return success. + */ +static int +read_map (CORE_ADDR mapp, struct thread_map *map) +{ + return base_ops.to_xfer_memory ((CORE_ADDR)THR_MAP (mapp), (char *)map, + sizeof (*map), 0, &base_ops); +} + +/* + * Read into LWP the contents of the lwp decriptor at inferior process address + * LWPP. Return success. + */ +static int +read_lwp (CORE_ADDR lwpp, __lwp_desc_t *lwp) +{ + return base_ops.to_xfer_memory (lwpp, (char *)lwp, + sizeof (*lwp), 0, &base_ops); +} + +/* + * Iterate through all user threads, applying FUNC(, , DATA) until + * (a) FUNC returns nonzero, + * (b) FUNC has been applied to all threads, or + * (c) an error occurs, + * where is the thread's struct thread_map and if non-null is the + * thread's current __lwp_desc_t. + * + * If a call to FUNC returns nonzero, return that value; otherwise, return 0. + */ +static int +thread_iter (int (*func)(iter_t *, void *), void *data) +{ + struct thread_debug debug; + CORE_ADDR first, mapp; + iter_t iter; + int ret; + + if (!read_thr_debug (&debug)) + return 0; + if (!base_ops.to_xfer_memory ((CORE_ADDR)debug.thr_map, (char *)&mapp, + sizeof (mapp), 0, &base_ops)) + return 0; + if (!mapp) + return 0; + + for (first = mapp;;) + { + if (!read_map (mapp, &iter.map)) + return 0; + + if (iter.map.thr_lwpp) + if (!read_lwp ((CORE_ADDR)iter.map.thr_lwpp, &iter.lwp)) + return 0; + + iter.mapp = mapp; + if ((ret = func (&iter, data))) + return ret; + + mapp = (CORE_ADDR)iter.map.thr_next; + if (mapp == first) + return 0; + } +} + +/* + * Deactivate user-mode thread support. + */ +static void +deactivate_uw_thread (void) +{ + uw_thread_active = 0; + unpush_target (&uw_thread_ops); +} + +/* + * Return the composite lwp/process id corresponding to composite + * id PID. If PID is a thread with no lwp, return 0. + */ +static int +thr_to_lwp (int pid) +{ + struct thread_info *info; + int lid; + + if (!ISTID (pid)) + lid = pid; + else if (!(info = find_thread_pid (pid))) + lid = 0; + else if (!info->private->lwpid) + lid = 0; + else + lid = MKLID (pid, info->private->lwpid); + + DBG2((" thr_to_lwp(%s) = %s", dbgpid (pid), dbgpid (lid))); + return lid; +} + +/* + * find_thread_lwp() callback: return whether TP describes a thread + * associated with lwp id DATA. + */ +static int +find_thread_lwp_callback (struct thread_info *tp, void *data) +{ + int lwpid = (int)data; + + if (!ISTID (tp->pid)) + return 0; + if (!tp->private->stable) + return 0; + if (lwpid != tp->private->lwpid) + return 0; + + /* match */ + return 1; +} + +/* + * If a thread is associated with lwp id LWPID, return the corresponding + * member of the global thread list; otherwise, return null. + */ +static struct thread_info * +find_thread_lwp (int lwpid) +{ + return iterate_over_threads (find_thread_lwp_callback, (void *)lwpid); +} + +/* + * Return the composite thread/process id corresponding to composite + * id PID. If PID is an lwp with no thread, return PID. + */ +static int +lwp_to_thr (int pid) +{ + struct thread_info *info; + int tid = pid, lwpid; + + if (ISTID (pid)) + goto done; + if (!(lwpid = LIDGET (pid))) + goto done; + if (!(info = find_thread_lwp (lwpid))) + goto done; + tid = MKTID (pid, info->private->thrid); + + done: + DBG2((ISTID (tid) ? NULL : "lwp_to_thr: no thr for %s", dbgpid (pid))); + return tid; +} + +/* + * do_cleanups() callback: convert inferior_pid to a composite + * thread/process id after having made a procfs call. + */ +static void +thr_infpid (void *unused) +{ + int pid = lwp_to_thr (inferior_pid); + DBG2((" inferior_pid from procfs: %s => %s", + dbgpid (inferior_pid), dbgpid (pid))); + inferior_pid = pid; +} + +/* + * If possible, convert inferior_pid to a composite lwp/process id in + * preparation for making a procfs call. Return success. + */ +static int +lwp_infpid (void) +{ + int pid = thr_to_lwp (inferior_pid); + DBG2((" inferior_pid to procfs: %s => %s", + dbgpid (inferior_pid), dbgpid (pid))); + + if (!pid) + return 0; + + inferior_pid = pid; + infpid_cleanup = make_cleanup (thr_infpid, NULL); + return 1; +} + +/* + * Add to the global thread list a new user-mode thread with system id THRID, + * lwp id LWPID, map address MAPP, and composite thread/process PID. + */ +static void +add_thread_uw (int thrid, int lwpid, CORE_ADDR mapp, int pid) +{ + struct thread_info *newthread; + + if ((newthread = add_thread (pid)) == NULL) + error ("failed to create new thread structure"); + + newthread->private = xmalloc (sizeof (struct private_thread_info)); + newthread->private->stable = 1; + newthread->private->thrid = thrid; + newthread->private->lwpid = lwpid; + newthread->private->mapp = mapp; + + if (target_has_execution) + printf_unfiltered ("[New %s]\n", target_pid_to_str (pid)); +} + +/* + * notice_threads() and find_main() callback: if the thread list doesn't + * already contain the thread described by ITER, add it if it's the main + * thread or if !DATA. + */ +static int +notice_thread (iter_t *iter, void *data) +{ + int thrid = iter->map.thr_tid; + int lwpid = !iter->map.thr_lwpp ? 0 : iter->lwp.lwp_id; + int pid = MKTID (inferior_pid, thrid); + + if (!find_thread_pid (pid) && (!data || thrid == 1)) + add_thread_uw (thrid, lwpid, iter->mapp, pid); + + return 0; +} + +/* + * Add to the thread list any threads it doesn't already contain. + */ +static void +notice_threads (void) +{ + thread_iter (notice_thread, NULL); +} + +/* + * Return the address of the main thread's map. On error, return 0. + */ +static CORE_ADDR +find_main (void) +{ + if (!thr_map_main) + { + struct thread_info *info; + thread_iter (notice_thread, (void *)1); + if ((info = find_thread_pid (MKTID (inferior_pid, 1)))) + thr_map_main = info->private->mapp; + } + return thr_map_main; +} + +/* + * Attach to process specified by ARGS, then initialize for debugging it + * and wait for the trace-trap that results from attaching. + * + * This function only gets called with uw_thread_active == 0. + */ +static void +uw_thread_attach (char *args, int from_tty) +{ + procfs_ops.to_attach (args, from_tty); + if (uw_thread_active) + thr_infpid (NULL); +} + +/* + * Detach from the process attached to by uw_thread_attach(). + */ +static void +uw_thread_detach (char *args, int from_tty) +{ + deactivate_uw_thread (); + base_ops.to_detach (args, from_tty); +} + +/* + * Tell the inferior process to continue running thread PID if >= 0 + * and all threads otherwise. + */ +static void +uw_thread_resume (int pid, int step, enum target_signal signo) +{ + if (pid > 0 && !(pid = thr_to_lwp (pid))) + pid = -1; + + CALL_BASE (base_ops.to_resume (pid, step, signo)); +} + +/* + * If the trap we just received from lwp PID was due to a breakpoint + * on the libthread.so debugging stub, update this module's state + * accordingly. + */ +static void +libthread_stub (int pid) +{ + CORE_ADDR sp, mapp, mapp_main; + enum thread_change change; + struct thread_map map; + __lwp_desc_t lwp; + int tid = 0, lwpid; + struct thread_info *info; + + /* Check for stub breakpoint. */ + if (read_pc_pid (pid) - DECR_PC_AFTER_BREAK != thr_brk_addr) + return; + + /* Retrieve stub args. */ + sp = read_register_pid (SP_REGNUM, pid); + if (!base_ops.to_xfer_memory (sp + SP_ARG0, (char *)&mapp, + sizeof (mapp), 0, &base_ops)) + goto err; + if (!base_ops.to_xfer_memory (sp + SP_ARG0 + sizeof (mapp), (char *)&change, + sizeof (change), 0, &base_ops)) + goto err; + + /* create_inferior() may not have finished yet, so notice the main + thread to ensure that it's displayed first by add_thread(). */ + mapp_main = find_main (); + + /* Notice thread creation, deletion, or stability change. */ + switch (change) { + case tc_switch_begin: + if (!mapp) /* usually means main thread */ + mapp = mapp_main; + /* fall through */ + + case tc_thread_create: + case tc_thread_exit: + if (!mapp) + break; + if (!read_map (mapp, &map)) + goto err; + tid = MKTID (pid, map.thr_tid); + + switch (change) { + case tc_thread_create: /* new thread */ + if (!map.thr_lwpp) + lwpid = 0; + else if (!read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp)) + goto err; + else + lwpid = lwp.lwp_id; + add_thread_uw (map.thr_tid, lwpid, mapp, tid); + break; + + case tc_thread_exit: /* thread has exited */ + printf_unfiltered ("[Exited %s]\n", target_pid_to_str (tid)); + delete_thread (tid); + if (tid == inferior_pid) + inferior_pid = pid; + break; + + case tc_switch_begin: /* lwp is switching threads */ + if (switchto_thread) + goto err; + if (!(switchto_thread = find_thread_pid (tid))) + goto err; + switchto_thread->private->stable = 0; + break; + + default: + break; + } + break; + + case tc_switch_complete: /* lwp has switched threads */ + case tc_cancel_complete: /* lwp didn't switch threads */ + if (!switchto_thread) + goto err; + + if (change == tc_switch_complete) + { + /* + * If switchto_thread is the main thread, then (a) the corresponding + * tc_switch_begin probably received a null map argument and therefore + * (b) it may have been a spurious switch following a tc_thread_exit. + * + * Therefore, explicitly query the thread's lwp before caching it in + * its thread list entry. + */ + if (!read_map (switchto_thread->private->mapp, &map)) + goto err; + if (map.thr_lwpp) + { + if (!read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp)) + goto err; + if ((info = find_thread_lwp (lwp.lwp_id))) + info->private->lwpid = 0; + switchto_thread->private->lwpid = lwp.lwp_id; + } + } + + switchto_thread->private->stable = 1; + switchto_thread = NULL; + break; + + case tc_invalid: + case tc_thread_suspend: + case tc_thread_suspend_pending: + case tc_thread_continue: + err: + DBG(("unexpected condition in libthread_stub()")); + break; + } + + DBG2(("libthread_stub(%s): %s %s %s", dbgpid (pid), dbgpid (tid), + dbgchange (change), tid ? dbgstate (map.thr_state) : "")); +} + +/* + * Wait for thread/lwp/process ID if >= 0 or for any thread otherwise. + */ +static int +uw_thread_wait (int pid, struct target_waitstatus *status) +{ + if (pid > 0) + pid = thr_to_lwp (pid); + CALL_BASE (pid = base_ops.to_wait (pid > 0 ? pid : -1, status)); + + if (status->kind == TARGET_WAITKIND_STOPPED && + status->value.sig == TARGET_SIGNAL_TRAP) + libthread_stub (pid); + + return lwp_to_thr (pid); +} + +/* + * Tell gdb about the registers in the thread/lwp/process specified by + * inferior_pid. + */ +static void +uw_thread_fetch_registers (int regno) +{ + int called; + struct thread_info *info; + struct thread_map map; + + TRY_BASE (base_ops.to_fetch_registers (regno), &called); + if (called) + return; + + if (!(info = find_thread_pid (inferior_pid))) + return; + if (!read_map (info->private->mapp, &map)) + return; + + supply_gregset (&map.thr_ucontext.uc_mcontext.gregs); + supply_fpregset (&map.thr_ucontext.uc_mcontext.fpregs); +} + +/* + * Store gdb's current view of the register set into the thread/lwp/process + * specified by inferior_pid. + */ +static void +uw_thread_store_registers (int regno) +{ + CALL_BASE (base_ops.to_store_registers (regno)); +} + +/* + * Prepare to modify the registers array. + */ +static void +uw_thread_prepare_to_store (void) +{ + CALL_BASE (base_ops.to_prepare_to_store ()); +} + +/* + * Fork an inferior process and start debugging it. + * + * This function only gets called with uw_thread_active == 0. + */ +static void +uw_thread_create_inferior (char *exec_file, char *allargs, char **env) +{ + if (uw_thread_active) + deactivate_uw_thread (); + + procfs_ops.to_create_inferior (exec_file, allargs, env); + if (uw_thread_active) + { + find_main (); + thr_infpid (NULL); + } +} + +/* + * Kill and forget about the inferior process. + */ +static void +uw_thread_kill (void) +{ + base_ops.to_kill (); +} + +/* + * Clean up after the inferior exits. + */ +static void +uw_thread_mourn_inferior (void) +{ + remove_thread_event_breakpoints (); + deactivate_uw_thread (); + base_ops.to_mourn_inferior (); +} + +/* + * Return whether this module can attach to and run processes. + * + * This function only gets called with uw_thread_active == 0. + */ +static int +uw_thread_can_run (void) +{ + return procfs_suppress_run; +} + +/* + * Return whether thread PID is still valid. + */ +static int +uw_thread_alive (int pid) +{ + if (!ISTID (pid)) + return base_ops.to_thread_alive (pid); + + /* If it's in the thread list, it's valid, because otherwise + libthread_stub() would have deleted it. */ + return in_thread_list (pid); +} + +/* + * Add to the thread list any threads and lwps it doesn't already contain. + */ +static void +uw_thread_find_new_threads (void) +{ + CALL_BASE (if (base_ops.to_find_new_threads) + base_ops.to_find_new_threads ()); + notice_threads (); +} + +/* + * Return a string for pretty-printing PID in "info threads" output. + * This may be called by either procfs.c or by generic gdb. + */ +static char * +uw_thread_pid_to_str (int pid) +{ +#define FMT "Thread %d" + static char buf[sizeof (FMT) + 3 * sizeof (pid)]; + + if (!ISTID (pid)) + /* core_ops says "process foo", so call procfs_ops explicitly. */ + return procfs_ops.to_pid_to_str (pid); + + sprintf (buf, FMT, TIDGET (pid)); +#undef FMT + return buf; +} + +/* + * Return a string displaying INFO state information in "info threads" + * output. + */ +static char * +uw_extra_thread_info (struct thread_info *info) +{ + static char buf[80]; + struct thread_map map; + __lwp_desc_t lwp; + int lwpid; + char *name; + + if (!ISTID (info->pid)) + return NULL; + + if (!info->private->stable) + return "switching"; + + if (!read_map (info->private->mapp, &map)) + return NULL; + + if (!map.thr_lwpp || !read_lwp ((CORE_ADDR)map.thr_lwpp, &lwp)) + lwpid = 0; + else + lwpid = lwp.lwp_id; + + switch (map.thr_state) { + case TS_ONPROC: name = "running"; break; + case TS_SLEEP: name = "sleeping"; break; + case TS_RUNNABLE: name = "runnable"; break; + case TS_ZOMBIE: name = "zombie"; break; + case TS_SUSPENDED: name = "suspended"; break; +#ifdef TS_FORK + case TS_FORK: name = "forking"; break; +#endif + default: name = "confused"; break; + } + + if (!lwpid) + return name; + + sprintf (buf, "%s, LWP %d", name, lwpid); + return buf; +} + +/* + * Check whether libthread.so has just been loaded, and if so, try to + * initialize user-space thread debugging support. + * + * libthread.so loading happens while (a) an inferior process is being + * started by procfs and (b) a core image is being loaded. + * + * This function often gets called with uw_thread_active == 0. + */ +static void +libthread_init (void) +{ + struct minimal_symbol *ms; + struct thread_debug debug; + CORE_ADDR onp; + struct breakpoint *b; + int one = 1; + + /* Don't initialize twice. */ + if (uw_thread_active) + return; + + /* Check whether libthread.so has been loaded. */ + if (!(ms = lookup_minimal_symbol ("_thr_debug", NULL, NULL))) + return; + + /* Cache _thr_debug's address. */ + if (!(thr_debug_addr = SYMBOL_VALUE_ADDRESS (ms))) + return; + + /* Initialize base_ops.to_xfer_memory(). */ + base_ops = current_target; + + /* Load _thr_debug's current contents. */ + if (!read_thr_debug (&debug)) + return; + + /* User code (e.g. my test programs) may dereference _thr_debug, + making it availble to GDB before shared libs are loaded. */ + if (!debug.thr_map) + return; + + /* libthread.so has been loaded, and the current_target should now + reflect core_ops or procfs_ops. */ + push_target (&uw_thread_ops); /* must precede notice_threads() */ + uw_thread_active = 1; + + if (!target_has_execution) + + /* Locate threads in core file. */ + notice_threads (); + + else + { + /* Set a breakpoint on the stub function provided by libthread.so. */ + thr_brk_addr = (CORE_ADDR)debug.thr_brk; + if (!(b = create_thread_event_breakpoint (thr_brk_addr))) + goto err; + + /* Activate the stub function. */ + onp = (CORE_ADDR)&((struct thread_debug *)thr_debug_addr)->thr_debug_on; + if (!base_ops.to_xfer_memory ((CORE_ADDR)onp, (char *)&one, + sizeof (one), 1, &base_ops)) + { + delete_breakpoint (b); + goto err; + } + + /* Prepare for finding the main thread, which doesn't yet exist. */ + thr_map_main = 0; + } + + return; + + err: + warning ("uw-thread: unable to initialize user-mode thread debugging\n"); + deactivate_uw_thread (); +} + +/* + * target_new_objfile_hook callback. + * + * If OBJFILE is non-null, check whether libthread.so was just loaded, + * and if so, prepare for user-mode thread debugging. + * + * If OBJFILE is null, libthread.so has gone away, so stop debugging + * user-mode threads. + * + * This function often gets called with uw_thread_active == 0. + */ +static void +uw_thread_new_objfile (struct objfile *objfile) +{ + if (objfile) + libthread_init (); + + else if (uw_thread_active) + deactivate_uw_thread (); + + if (target_new_objfile_chain) + target_new_objfile_chain (objfile); +} + +/* + * Initialize uw_thread_ops. + */ +static void +init_uw_thread_ops (void) +{ + uw_thread_ops.to_shortname = "unixware-threads"; + uw_thread_ops.to_longname = "UnixWare threads and pthread."; + uw_thread_ops.to_doc = "UnixWare threads and pthread support."; + uw_thread_ops.to_attach = uw_thread_attach; + uw_thread_ops.to_detach = uw_thread_detach; + uw_thread_ops.to_resume = uw_thread_resume; + uw_thread_ops.to_wait = uw_thread_wait; + uw_thread_ops.to_fetch_registers = uw_thread_fetch_registers; + uw_thread_ops.to_store_registers = uw_thread_store_registers; + uw_thread_ops.to_prepare_to_store = uw_thread_prepare_to_store; + uw_thread_ops.to_create_inferior = uw_thread_create_inferior; + uw_thread_ops.to_kill = uw_thread_kill; + uw_thread_ops.to_mourn_inferior = uw_thread_mourn_inferior; + uw_thread_ops.to_can_run = uw_thread_can_run; + uw_thread_ops.to_thread_alive = uw_thread_alive; + uw_thread_ops.to_find_new_threads = uw_thread_find_new_threads; + uw_thread_ops.to_pid_to_str = uw_thread_pid_to_str; + uw_thread_ops.to_extra_thread_info = uw_extra_thread_info; + uw_thread_ops.to_stratum = thread_stratum; + uw_thread_ops.to_magic = OPS_MAGIC; +} + +/* + * Module startup initialization function, automagically called by + * init.c. + */ +void +_initialize_uw_thread (void) +{ + init_uw_thread_ops (); + add_target (&uw_thread_ops); + + procfs_suppress_run = 1; + + /* Notice when libthread.so gets loaded. */ + target_new_objfile_chain = target_new_objfile_hook; + target_new_objfile_hook = uw_thread_new_objfile; +} diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c index 060200f..5f71b5e 100644 --- a/gdb/v850-tdep.c +++ b/gdb/v850-tdep.c @@ -869,6 +869,7 @@ v850_target_architecture_hook (ap) if (v850_processor_type_table[i].mach == ap->mach) { v850_register_names = v850_processor_type_table[i].regnames; + tm_print_insn_info.mach = ap->mach; return 1; } } diff --git a/sim/mcore/ChangeLog b/sim/mcore/ChangeLog index 0dca474..a43e7cb 100644 --- a/sim/mcore/ChangeLog +++ b/sim/mcore/ChangeLog @@ -1,3 +1,8 @@ +2000-01-13 Nick Clifton + + * interp.c (sim_resume): Do not rely upon host semantics of shift + operators to implement M*Core semantics. + Thu Sep 2 18:15:53 1999 Andrew Cagney * configure: Regenerated to track ../common/aclocal.m4 changes. diff --git a/sim/mcore/interp.c b/sim/mcore/interp.c index 810bb06..899b371 100644 --- a/sim/mcore/interp.c +++ b/sim/mcore/interp.c @@ -1181,7 +1181,9 @@ sim_resume (sd, step, siggnal) unsigned long dst, src; dst = cpu.gr[RD]; src = cpu.gr[RS]; - dst = dst >> src; + /* We must not rely solely upon the native shift operations, since they + may not match the M*Core's behaviour on boundary conditions. */ + dst = src > 31 ? 0 : dst >> src; cpu.gr[RD] = dst; } break; @@ -1256,11 +1258,18 @@ sim_resume (sd, step, siggnal) break; case 0x1A: /* asr */ - cpu.gr[RD] = (long)cpu.gr[RD] >> cpu.gr[RS]; + /* We must not rely solely upon the native shift operations, since they + may not match the M*Core's behaviour on boundary conditions. */ + if (cpu.gr[RS] > 30) + cpu.gr[RD] = ((long) cpu.gr[RD]) < 0 ? -1 : 0; + else + cpu.gr[RD] = (long) cpu.gr[RD] >> cpu.gr[RS]; break; case 0x1B: /* lsl */ - cpu.gr[RD] = cpu.gr[RD] << cpu.gr[RS]; + /* We must not rely solely upon the native shift operations, since they + may not match the M*Core's behaviour on boundary conditions. */ + cpu.gr[RD] = cpu.gr[RS] > 31 ? 0 : cpu.gr[RD] << cpu.gr[RS]; break; case 0x1C: /* addu */ -- 2.7.4