2002-08-28 Andrew Cagney From Fernando Nasser: * Makefile.in (ALLDEPFILES): Add i386-cpuid.c. (i386-cpuid.o): Specify dependencies. (install-cpuid): New target. (uninstall-cpuid): New target. (cpuid): New target. (CPUID): Define. (GDB_CFLAGS): Add SHAREDIR. * config/i386/embed.mt (TDEPFILES): Add i386-cpuid.o. * remote.c (remote_start_remote): Call target_post_open_hook. * utils.c (target_post_open_hook): Define. * target.h (target_post_open_hook): Declare. * cpuid-i386: New file. * i386-cpuid.c: New file. * configure.tgt (CONFIG_ALL): Add cpuid. (CONFIG_INSTALL): Add install-cpuid. (CONFIG_UNINSTALL): Add uninstall-cpuid. Index: Makefile.in =================================================================== RCS file: /cvs/src/src/gdb/Makefile.in,v retrieving revision 1.252 diff -u -r1.252 Makefile.in --- Makefile.in 28 Aug 2002 14:02:18 -0000 1.252 +++ Makefile.in 28 Aug 2002 21:22:13 -0000 @@ -319,7 +319,7 @@ # your system doesn't have fcntl.h in /usr/include (which is where it # should be according to Posix). DEFS = @DEFS@ -GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config -DLOCALEDIR="\"$(prefix)/share/locale\"" $(DEFS) +GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config -DLOCALEDIR="\"$(prefix)/share/locale\"" -DSHAREDIR="\"$(prefix)/share\"" $(DEFS) # M{H,T}_CFLAGS, if defined, have host- and target-dependent CFLAGS # from the config directory. @@ -939,6 +939,31 @@ $(INSTALL_DATA) $$i $(GDBTK_LIBRARY)/$$i ; \ done ; + +# Build/install any CPU IDs. + +CPUID=cpuid-i386 +install-cpuid: force + $(SHELL) $(srcdir)/../mkinstalldirs $(datadir)/gdb ; \ + for i in $(CPUID) ; \ + do \ + $(INSTALL_DATA) $$i $(datadir)/gdb/$$i ; \ + done ; +uninstall-cpuid: force + for c in $(CPUID) ; \ + do \ + rm -f $(datadir)/gdb/$$c ; \ + done ; +cpuid: force + for i in $(CPUID) ; do \ + if test ! -f ./$$i ; then \ + (test "$$LN_S" = "ln -s" && ln -s $(srcdir)/$$i .) || \ + ln $(srcdir)/$$i . || \ + cp $(srcdir)/$$i ; \ + fi ; \ + done + + # We do this by grepping through sources. If that turns out to be too slow, # maybe we could just require every .o file to have an initialization routine # of a given name (top.o -> _initialize_top, etc.). @@ -1356,6 +1381,7 @@ dcache.c delta68-nat.c dpx2-nat.c exec.c fork-child.c \ go32-nat.c h8300-tdep.c h8500-tdep.c \ hp300ux-nat.c hppa-tdep.c hppab-nat.c hppah-nat.c hpread.c \ + i386-cpuid.c \ i386-tdep.c i386b-nat.c i386v-nat.c i386-linux-nat.c \ i386v4-nat.c i386ly-tdep.c \ i386bsd-nat.c i386bsd-tdep.c i386fbsd-nat.c \ @@ -1725,6 +1751,8 @@ $(gdb_string_h) hpux-thread.o: hpux-thread.c $(defs_h) $(gdbthread_h) $(target_h) \ $(inferior_h) $(regcache_h) $(gdbcore_h) +i386-cpuid.o: i386-cpuid.c $(defs_h) $(target_h) $(command_h) $(gdbcmd_h) \ + $(gdb_string_h) i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(regcache_h) $(gdb_assert_h) $(gdb_string_h) $(gregset_h) \ $(i387_tdep_h) $(i386_tdep_h) $(i386_linux_tdep_h) Index: configure.tgt =================================================================== RCS file: /cvs/src/src/gdb/configure.tgt,v retrieving revision 1.84 diff -u -r1.84 configure.tgt --- configure.tgt 22 Aug 2002 21:52:44 -0000 1.84 +++ configure.tgt 28 Aug 2002 21:22:13 -0000 @@ -118,7 +118,11 @@ # OBSOLETE i[3456]86-*-osf1mk*) gdb_target=i386mk ;; i[3456]86-*-cygwin*) gdb_target=cygwin ;; i[3456]86-*-vxworks*) gdb_target=vxworks ;; -i[3456]86-*-*) gdb_target=embed ;; +i[3456]86-*-*) gdb_target=embed + CONFIG_ALL="$(CONFIG_ALL) cpuid" + CONFIG_INSTALL="${CONFIG_INSTALL} install-cpuid" + CONFIG_UNINSTALL="${CONFIG_UNINSTALL} install-cpuid" + ;; # OBSOLETE i960-*-bout*) gdb_target=vxworks960 ;; # OBSOLETE i960-nindy-coff*) gdb_target=nindy960 ;; Index: cpuid-i386 =================================================================== RCS file: cpuid-i386 diff -N cpuid-i386 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ cpuid-i386 28 Aug 2002 21:22:13 -0000 @@ -0,0 +1,80 @@ +# Intel i386 CPUID database, for GDB, the GNU Debugger. +# +# Copyright 2002 Free Software Foundation, Inc. +# +# Contributed by Red Hat, 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. +# +# This file describes the known CPUID codes for Intel processors +# +# The format is as follows: +# +# TFMScXXXXXXXXXX....XXXXXXXXX +# where +# T = Type +# F = Family +# M = Model +# S = Stepping (a 'x' matches any value) +# c = Cache size code if model 5 or 7 (for ambiguous FMS combinations) +# Brand Id if model 8 or higher (for ambiguous FMS combinations) +# XXXXXXX....XXXXXXXX = String describing the processor +# +# Lines cannot be longer than 80 bytes. +# The first match wins, so place entries with a specific stepping before +# the entry with a generic specifier ('x'). +# "Genuine Intel" will be added automatically if that is verified. +# As you may have guessed, lines stating with a '#' are comments. +# +# Note: make install copies this file to $(install_dir)/share/gdb/cpuid-i386 +# +040x 486(TM) DX processor +041x 486(TM) DX processor +042x 486(TM) SX processor +043x DX2(TM) processor +044x 486(TM) processor +045x SX2(TM) processor +047x Write-Back Enhanced DX2(TM) processor +048x DX4(TM) processor +148x DX4(TM) OverDrive processor +051x Pentium(R) processor +151x Pentium(R) OverDrive processor for Pentium processor +052x Pentium(R) processor +152x Pentium(R) OverDrive processor for Pentium processor +053x Pentium(R) OverDrive processor for Intel 486 processor-based systems +054x Pentium(R) processor with MMX technology +154x Pentium(R) OverDrive processor with MMX technology for Pentium processor +061x Pentium(R) Pro processor +063x Pentium(R) II processor, model 3 +163x Pentium(R) II OverDrive processor +065x0Celeron(TM) processor, model 5 +065x3Pentium(R) II processor, model 5 or Pentium(R) II Xeon(TM) processor +065x4Pentium(R) II Xeon(TM) processor +065x5Pentium(R) II Xeon(TM) processor +066A Pentium(R) II processor [Dixon] +066x Celeron(TM) processor, model 6 +067x3Pentium(R) III processor or Intel Pentium(R) III Xeon processor +067x4Pentium(R) III Xeon(TM) processor +067x5Pentium(R) III Xeon(TM) processor +06800Pentium(R) III processor [Coppermine] +068x1Celeron(TM) processor +066A Celeron(TM) processor +063x Pentium(R) II processor +06Ax Pentium(R) III processor +068x2Pentium(R) III processor +068x3Pentium(R) III Xeon(TM) processor Index: i386-cpuid.c =================================================================== RCS file: i386-cpuid.c diff -N i386-cpuid.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ i386-cpuid.c 28 Aug 2002 21:22:14 -0000 @@ -0,0 +1,340 @@ +/* Intel 386 CPUID command for GDB, the GNU Debugger. + + Copyright 2002 Free Software Foundation, Inc. + + Contributed by Red Hat, 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. */ + +#include "defs.h" +#include "target.h" +#include "command.h" +#include "gdbcmd.h" +#include "gdb_string.h" + +/* NOTE: cagney/2001-11-17: + + This module uses the [remote protocol] target_query ("qCPUID") + method to extract the i386 CPU information. It then takes that + information and uses it to do a lookup on a local file + ``cpuid-i386''. + + Thanks to a botched initial thread query mechanism, using anything + starting with ``qC'' is dangerous. Since qCPUID does this, it + won't interact well with targets that recognize the exiting ``qC'' + query. Sigh. + + One possible alternative to this qCPUID mechanis would be to plant + a CPUID instruction in the target memory, execute it, and then + examine the result. This probably isn't pratical since it depends + in being able to execute code in the target. + + This file adds the command ``info cpu''. Beware of the existing + commands ``{set,show} {processor,architecture}''. + + This file uses a target_post_open_hook() mechanism to hook into the + target open (and report the CPUID on an initial connect). Per the + comment in the file "target.h", what really should be happening is + a core_gdb_open() function should be calling the hook. */ + +#include + +#ifndef GDBCPUID_FILENAME +#define GDBCPUID_FILENAME "cpuid-i386" +#endif + +/* Helper for CPUID handler. */ + +static int +toint (char c) +{ + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + /* c is not an hex digit */ + return 0; +} + +/* Get CPUID from the target, if available. + The returned null terminated string is of the form: + ITFMSC + where + I = Genuine modifier + "I" if this is a Genuine Intel CPU, "N" otherwise; + T = Processor Type; + F = Processor Family; + M = Processor Model; + S = Processor Stepping; + C = Cache modifier + The cache descriptor value if between 0x40 and 0x49, a space otherwise. + This modifier is only non-blank for some ambiguous cases where the + Family+Model is not enough to distinguish the processors. +*/ + +static char * +i386_get_cpuid (void) +{ + static char genuine[] = "756e6547,6c65746e,49656e69"; + static char Genuine[] = "756E6547,6C65746E,49656E69"; + int size = 0; + char *buf; + char *rets; + + /* Is this even supported? */ + if (current_target.to_query == NULL) + return NULL; + + /* Get the current buffer size. Ignore the error return status as + this call always fails. */ + size = 0; + target_query ('C', "PUID", NULL, &size); + + buf = xmalloc (size); + /* Now query the CPUID info. */ + if (target_query ('C', "PUID", buf, &size) < 0) + return NULL; + + /* Check if we got enough data and do some ad hoc consistence checking. */ + size = strlen(buf); + if ((size < 44) + || (buf[35] != ';') + || (buf[8] != ',')) + /* No valid CPUID information available. */ + return NULL; + + /* Get enough space for the returned string. */ + rets = xmalloc (7 * sizeof(*rets)); + if (rets == NULL) + internal_error (__FILE__, __LINE__, + "Gdb cannot allocate memory. Memory exhausted?"); + + /* Copy the basic information, leaving space for the modifiers. */ + rets[0] = 'N'; /* It is not Intel until proved genuine. */ + rets[1] = buf[40] & 0xf3; /* Processor Type (just 2 bits). */ + rets[2] = /* Processor Family. */ + islower (buf[41]) ? toupper (buf[41]) : buf[41]; + rets[3] = /* Processor Model. */ + islower (buf[42]) ? toupper (buf[42]) : buf[42]; + rets[4] = /* Processor Stepping. */ + islower (buf[43]) ? toupper (buf[43]) : buf[43]; + rets[5] = ' '; /* No Cache modifier unless needed. */ + rets[6] = '\0'; /* String terminator. */ + + /* Check if this is a Genuine Intel processor. */ + buf[35] = '\0'; + if ((strcmp (Genuine, &buf[9]) == 0) + || (strcmp (genuine, &buf[9]) == 0)) + /* It is a Genuine Intel processor. */ + rets[0] = 'I'; + + /* If one of the ambiguous cases, check for cache size, + but check if we have enough information first. */ + if ((size >= 107) + && ((buf[41] == '6') && ((buf[42] == '5') || (buf[42] == '7')))) + { + int i; + for (i = 72; i <= 107; i = i + 2) + if ((buf[i] == '4') + && (buf[i + 1] >= '0') + && (buf[i + 1] <= '9')) + { + rets[5] = buf[i + 1]; + break; + } + } + + /* CPUs from model 8 onwards have a Brand Id field */ + if ((size >= 53) + && ((toint(buf[41]) >= 6) && (toint(buf[42]) >= 8))) + { + rets[5] = toint(buf[52]) | 0x30; + } + + free (buf); + return rets; +} + +/* Check our database for description of cpu with this CPUID. */ + +char * +i386_get_cpuid_string (char * cpuid) +{ + FILE *cpufp; + char *cpuidtxt; + char *retstr; + /* These paths are for when gdb is run from the build tree (like in + "make check"). It can be invoked from different levels. */ + char *build_paths[] = { "/", + "/../", + "/gdb/", + NULL + }; + int idind; + char filename[] = GDBCPUID_FILENAME; + char str[82]; + char cpuidx[5]; + char *xfilename; + char *gdb_exec_prefix = getenv ("GDB_EXEC_PREFIX"); + + cpufp = NULL; + + /* Look in the standard directories. */ + xasprintf (&xfilename, "%s/gdb/%s", SHAREDIR, GDBCPUID_FILENAME); + cpufp = fopen (xfilename, "r"); + free (xfilename); + + /* If not found, look in the build tree. */ + idind = 0; + while ((cpufp == NULL) && (build_paths[idind] != NULL)) + { +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + xfilename = malloc (PATH_MAX + + strlen (build_paths[idind]) + + sizeof (GDBCPUID_FILENAME) + 1); + if (getcwd (xfilename, PATH_MAX) != NULL) + { + strcat (xfilename, build_paths[idind]); + strcat (xfilename, filename); + cpufp = fopen (xfilename, "r"); + free (xfilename); + } + idind++; + } + + if (cpufp == NULL) + { + warning ("Cannot find/open %s file.", filename); + return NULL; + } + + /* Create a pattern to match the any stepping rule. */ + cpuidx[0] = cpuid[1]; + cpuidx[1] = cpuid[2]; + cpuidx[2] = cpuid[3]; + cpuidx[3] = 'x'; /* 'x' denotes any stepping matches entry. */ + cpuidx[4] = cpuid[5]; + + /* Look in the file for an entry with this CPUID hex string + or with the catch all steppings one. */ + do + { + cpuidtxt = fgets (str, 81, cpufp); + if (ferror (cpufp)) + { + warning ("Error reading %s file.\n", filename); + break; + } + if (cpuidtxt == NULL) + break; + /* skip comment lines. + Not really necessary, but avoid unneeded comparison */ + if (*cpuidtxt == '#') + continue; + } + while (strncmp (cpuidtxt, (cpuid + 1), 5) + && strncmp (cpuidtxt, cpuidx, 5)); + + fclose (cpufp); + + /* A valid entry has 5 cpuid hex digits and the description. + Note that fgets() includes the new-line in the string. */ + if ((cpuidtxt != NULL) && (strlen (cpuidtxt) > 7)) + /* Skip the id and point to the description text. */ + cpuidtxt += 5; + else + /* Empty description texts are not accepted. */ + return NULL; + + /* Check for Genuine Intel and add that to the string if it is the case. */ + if (*cpuid == 'I') + { + retstr = xmalloc (strlen (cpuidtxt) + 15); + strncpy (retstr, "Genuine Intel ", 14); + strcpy ((retstr + 14), cpuidtxt); + } + else + retstr = xstrdup (cpuidtxt); + + return retstr; +} + +/* Prints CPUID information (info cpu). */ + +/* ARGSUSED */ +static void +i386_info_cpu_cmd (char *args, int from_tty) +{ + char *id; + char *msg; + + id = i386_get_cpuid (); + if (id == NULL) + { + printf_filtered ("CPU information not available.\n"); + return; + } + + msg = i386_get_cpuid_string (id); + if (msg == NULL) + { + printf_filtered ("Unidentified CPU (CPUID=%s)\n", id); + printf_filtered ("Processor Family: %c Model: %c Stepping: %c\n", + id[2], id[3], id[4]); + free (id); + return; + } + else + { + printf_filtered ("%s", msg); + printf_filtered ("Processor Family: %c Model: %c Stepping: %c\n", + id[2], id[3], id[4]); + } + + free (msg); + free (id); +} + +/* Done after remote connects to a target. */ + +static void (*i386_cpuid_post_open_chain) (void); + +static void +i386_cpuid_post_open (void) +{ + /* Print CPUID information. */ + i386_info_cpu_cmd (NULL, 1); + /* Call the next thing on the list. */ + if (i386_cpuid_post_open_chain != NULL) + i386_cpuid_post_open_chain (); +} + +extern initialize_file_ftype _initialize_i386_cpuid; +void +_initialize_i386_cpuid () +{ + /* Insert this modules post open into the post_open chain. */ + i386_cpuid_post_open_chain = target_post_open_hook; + target_post_open_hook = i386_cpuid_post_open; + + /* Add "info cpu" command. */ + add_cmd ("cpu", class_info, i386_info_cpu_cmd, + "Show information about the target cpu", + &infolist); +} Index: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.93 diff -u -r1.93 remote.c --- remote.c 18 Aug 2002 23:17:57 -0000 1.93 +++ remote.c 28 Aug 2002 21:22:16 -0000 @@ -2141,6 +2141,11 @@ get_offsets (); /* Get text, data & bss offsets */ + /* Give any interested spectators a chance to do something based on + the opening of a new target connection. */ + if (target_post_open_hook != NULL) + target_post_open_hook (); + putpkt ("?"); /* initiate a query from remote machine */ immediate_quit--; Index: target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.26 diff -u -r1.26 target.h --- target.h 26 Aug 2002 19:18:33 -0000 1.26 +++ target.h 28 Aug 2002 21:22:16 -0000 @@ -1002,6 +1002,22 @@ extern void (*target_new_objfile_hook) (struct objfile *); +/* target_post_open_hook: This hack makes it possible for modules to + do extra work at the end of a target_open(). Functions using this + should chain their calls, see target_new_objfile_hook. + + FIXME: cagney/2001-11-17: What should happen is: user enters + ``(gdb) target blah''; cli calls ``core-gdb target open (blah)''; + that core code does generic pre-processing, and then calls + ``blah.open()''; if ``blah.open()'' succeeds, the core code calls + any post processing which might include this hook. Why hasn't this + been done? Well it turns out that ``(gdb) target blah'' is + implemented as a call direct to blah.open(). Core GDB doesn't get + a look in. Fixing this involves changing the CLI interface so that + CLI methods get called with a local context - eg: + core_gdb_open(blah). */ +extern void (*target_post_open_hook) (void); + #ifndef target_pid_or_tid_to_str #define target_pid_or_tid_to_str(ID) \ target_pid_to_str (ID) Index: utils.c =================================================================== RCS file: /cvs/src/src/gdb/utils.c,v retrieving revision 1.76 diff -u -r1.76 utils.c --- utils.c 1 Aug 2002 17:18:33 -0000 1.76 +++ utils.c 28 Aug 2002 21:22:17 -0000 @@ -91,6 +91,9 @@ /* readline defines this. */ #undef savestring +/* Chain of functions that wan't to know when a remote open occures. */ +void (*target_post_open_hook) (void); + void (*error_begin_hook) (void); /* Holds the last error message issued by gdb */ Index: config/i386/embed.mt =================================================================== RCS file: /cvs/src/src/gdb/config/i386/embed.mt,v retrieving revision 1.3 diff -u -r1.3 embed.mt --- config/i386/embed.mt 18 Nov 2001 21:28:20 -0000 1.3 +++ config/i386/embed.mt 28 Aug 2002 21:22:17 -0000 @@ -1,3 +1,3 @@ # Target: Embedded Intel 386 -TDEPFILES= i386-tdep.o i387-tdep.o +TDEPFILES= i386-tdep.o i387-tdep.o i386-cpuid.o TM_FILE= tm-i386.h