Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!cs.utexas.edu!uunet!mcsun!ukc!icdoc!qmw-cs!liam From: liam@cs.qmw.ac.uk (William Roberts) Newsgroups: comp.unix.aux Subject: Re: How do you read symbols in /dev/kmem when nlist won't work Keywords: kernel Message-ID: <2343@sequent.cs.qmw.ac.uk> Date: 7 Jun 90 18:56:31 GMT References: <1990Jun6.003947.27323@portia.Stanford.EDU> Organization: Computer Science Dept, QMW, University of London, UK. Lines: 233 In <1990Jun6.003947.27323@portia.Stanford.EDU> name@portiaStanford.EDU (tony cooper) writes: >nlist is declared in A/UX starting as: >struct nlist { /* symbol table entry */ > char n_name[8]; /* symbol name */ >Well n_name is restricted to 8 bytes so names must be 7 bytes long or less. >So how do you read sysmbols that are longer than 7 characters? Close but no cigar. nlist is actually defined as #define nlist syment in both A/UX 1.1.1 and A/UX 2.0b10, so what you are getting is a struct syment. In order to allow backwards compatibility with the Stone Age, the first 8 bytes of the structure are defined in as union { char _n_name[SYMNMLEN]; /* old COFF version */ struct { long _n_zeroes; /* new == 0 */ long _n_offset; /* offset into string table */ } _n_n; char *_n_nptr[2]; /* allows for overlaying */ } _n; Symbols of up to 8 bytes are placed in _n_name by old-style compilers. New style compilers (e.g. the A/UX ones) set _n_zeroes to zero as a marker, and then put an offset into the string table in _n_offset. Naturally there are #defines to hide the _n union and the _n_n structure. Old and new styles don't mix (I don't think) and the syment() library routine returns the value associated with the symbol (normally an address) in n_value. >There are >plenty of symbols that are longer. Most other UNIXs declare char *n_name so >they don't have this problem. >The only source code example I have is xload. But it reads the symbol avenrun >which is 7 characters. Other A/UX programs can read longer sysmbols eg netstat >reads symbols longer than 7 such as icmpstat and rthashsize. (But most >symbol reading programs read short symbols only). **** WARNING: I am now speculating - see confession below **** As explained above, you can still do this, but you need 4 zero bytes first to show that this is what you are doing. This is a snag for the standard BSD cliche, namely struct nlist Nl[] = { { "icmpstat" }, #define NL_ICMPSTAT 0 { "rthashsize" }, #define NL_RTHASHSIZE 1 0 }; Why? Because you can't declare a static initialiser for a union. I've been think about this today (and running adb on the nlist.o file from libc.a, which is where I gleaned the above details) and my considered solution is as follows: Replace the existing nlist.h with the one from the shar file given below. Edit your code so that it converts anything of the form shown above into the the following form struct nlist_syment Nl[] = { NLIST_ENTRY("icmpstat"), #define NL_ICMPSTAT 0 NLIST_ENTRY("rthashsize"), #define NL_RTHASHSIZE 1 NLIST_ENTRY(0) }; You haven't got real source code compatibility anyway, and I think that the above change is small enough to be OK for the simple things: obviously anything which uses fields other than n_name and n_value are going to need extensive rewriting. In the longer term, perhaps Apple could simply abandon the defunct 8 character limit on symbol names, though this still won't help make BSD and SysV completely interchangeable. Here's my replacement for nlist.h and a little demo program. I have to confess that the test program seems unable to read quite a variety of symbols which definitely DO exist - anyone know what I haven't got quite right? # cc -o nlist_test nlist_test.c; nlist_test symbol icmpstat has value 0x0 (type 0) symbol rthashsize has value 0x110087c0 (type 0) symbol icmp_input has value 0x1004990e (type 0) symbol avenrun has value 0x0 (type 0) symbol icmproto has value 0x0 (type 0) # nm -x /unix | egrep "icmpstat|rthashsize|icmp_input|avenrun|icmproto" icmproto |0x11008d20|static| | | |.data avenrun |0x12011440|extern| | | |.bss rthashsize |0x110087c0|extern| | | |.data icmp_input |0x1004990e|extern| | | |.text icmpstat |0x12017c34|extern| | | |.bss # Just as well I decided to test it :-( # This is a shar archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #--------cut--------cut--------cut--------cut--------cut-------- #! /bin/sh # shar: Shell Archiver # Run the following with /bin/sh to create: # nlist.h # nlist_test.c # This archive created: Thu Jun 7 19:47:30 WET DST 1990 echo shar: extracting "nlist.h" '('1498 chars')' if test -f nlist.h then echo shar: will not overwrite existing file "nlist.h" else cat << \SHAR_EOF > nlist.h /* Imitation nlist.h file for rough and ready compatibility between * the BSD style of doing things and SysV * * Use this file in preference to a.out.h for BSD files, though * you might want to convert over entirely to the SysV scheme. * * William Roberts QMW, University of London 7th June 1990 */ #ifndef __NLIST__ #define __NLIST__ struct nlist_syment { long n_zeroes; /* must be 0 */ char *n_name; /* offset into string table */ long n_value; /* value of symbol */ short n_scnum; /* section number */ unsigned short n_type; /* type and derived type */ char n_sclass; /* storage class */ char n_numaux; /* number of aux. entries */ }; #define nlist syment #define NLIST_ENTRY(s) {0, (s)} /* The tradition BSD cliche of * * struct nlist nl[] = { * { "name1" }, * { "name2" }, * { "" } * } * * should be converted to * * struct nlist_syment nl[] = { * NLIST_ENTRY("name1"), * NLIST_ENTRY("name2"), * NLIST_ENTRY(0) * }; * * Note that you probably won't get away with using an empty string as the * end marker rather than NULL. * * You need the struct nlist_syment as defined above otherwise you will get * the struct syment which includes a union and so can't be given a * static initialiser. */ #endif SHAR_EOF if test 1498 -ne `wc -c < nlist.h` then echo shar: error transmitting "nlist.h" '('should be 1498 chars')' else echo nlist.h fi fi echo shar: extracting "nlist_test.c" '('494 chars')' if test -f nlist_test.c then echo shar: will not overwrite existing file "nlist_test.c" else cat << \SHAR_EOF > nlist_test.c #include #include "nlist.h" struct nlist_syment Nl[] = { NLIST_ENTRY("icmpstat"), NLIST_ENTRY("rthashsize"), NLIST_ENTRY("icmp_input"), NLIST_ENTRY("avenrun"), NLIST_ENTRY("icmproto"), NLIST_ENTRY(0) }; main() { int i; i = nlist("/unix", Nl); if (i < 0) { perror("nlist"); } else { for (i=0; Nl[i].n_name != 0; i++) { printf("symbol %s has value 0x%x (type %d)\n", Nl[i].n_name, Nl[i].n_value, Nl[i].n_type); } } } SHAR_EOF if test 494 -ne `wc -c < nlist_test.c` then echo shar: error transmitting "nlist_test.c" '('should be 494 chars')' else echo nlist_test.c fi fi # End of shar archive exit 0 -- William Roberts ARPA: liam@cs.qmw.ac.uk Queen Mary & Westfield College UUCP: liam@qmw-cs.UUCP Mile End Road AppleLink: UK0087 LONDON, E1 4NS, UK Tel: 071-975 5250 (Fax: 081-980 6533)