use of new iterator style
[dyninst.git] / pdutil / h / Object-cm5.h
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /************************************************************************
43  * Object-bsd.h: BSD object files.
44 ************************************************************************/
45
46
47 \f
48
49
50 #if !defined(_Object_bsd_h_)
51 #define _Object_bsd_h_
52
53
54 /* 
55  *
56  * Note - this class reads the node portion of the "fat" a.out for the cm5.
57  *        The node portion will be the second half of the executable file
58  *        and its exact location can be determined by reading the end of
59  *        the file. 
60  * 
61  * code_ptr_ and data_ptr_ must be adjusted by this offset
62  * code_len_, data_len_, code_off_, and data_off_ must not since the addresses
63  *        in the node portion of the executable are not indexed from the
64  *        start of the file,
65  *
66  *            file[nodeFileOffset_] = node_portion_memory[0]
67  *
68  */
69
70 \f
71
72
73 /************************************************************************
74  * header files.
75 ************************************************************************/
76
77 #include <util/h/Dictionary.h>
78 #include <util/h/String.h>
79 #include <util/h/Symbol.h>
80 #include <util/h/Types.h>
81 #include <util/h/Vector.h>
82
83 #include <a.out.h>
84 #include <fcntl.h>
85 #include <stab.h>
86 #include <stdlib.h>
87 #include <unistd.h>
88
89 #include <sys/types.h>
90 #include <sys/mman.h>
91 #include <sys/stat.h>
92
93 extern "C" {
94 #include <cmsys/cm_a.out.h>
95 }
96
97
98 \f
99
100
101 /************************************************************************
102  * class Object
103 ************************************************************************/
104
105 class Object : public AObject {
106 public:
107              Object (const string, void (*)(const char *) = log_msg);
108              Object (const Object &);
109     virtual ~Object ();
110
111     Object&   operator= (const Object &);
112
113 private:
114     void    load_object ();
115     unsigned nodeFileOffset_;
116 };
117
118 static int symbol_compare(const void *x, const void *y) {
119     Symbol *s1 = (Symbol *)x;
120     Symbol *s2 = (Symbol *)y;
121     return (s1->addr() - s2->addr());
122 }
123
124 inline
125 void
126 Object::load_object() {
127     const char* file = file_.string_of();
128     struct stat st;
129     int         fd  = -1;
130     char*       ptr = 0;
131
132     bool        did_open = false;
133
134     /* try */ {
135         if (((fd = open(file, O_RDONLY)) == -1) || (fstat(fd, &st) == -1)) {
136             log_perror(err_func_, file);
137             /* throw exception */ goto cleanup;
138         }
139         did_open = true;
140
141         if ((ptr = (char *) mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
142             == (char *) -1) {
143             log_perror(err_func_, "mmap");
144             /* throw exception */ goto cleanup;
145         }
146
147         nodeFileOffset_ = st.st_size - sizeof(cm_par_id_t);
148         cm_par_id_t header;
149         memcpy((void*) &header, (void*)(ptr+nodeFileOffset_), sizeof(cm_par_id_t));
150         if (header.magic != CM_PAR_MAGIC) {
151           log_perror(err_func_, "Not a CM5 executable\n");
152           /* throw exception */ goto cleanup;
153         }
154
155         nodeFileOffset_ = header.par_offset;
156         struct exec* execp = (struct exec *) &ptr[nodeFileOffset_];
157         if (N_BADMAG(*execp)) {
158             /* throw exception */ goto cleanup;
159         }
160
161         code_ptr_ = (Word *) &ptr[unsigned(N_TXTOFF(*execp)+nodeFileOffset_)];
162         code_off_ = (unsigned) (N_TXTADDR(*execp));
163         code_len_ = unsigned(execp->a_text / sizeof(Word));
164
165         data_ptr_ = (Word *) &ptr[unsigned(N_DATOFF(*execp)+nodeFileOffset_)];
166         data_off_ = (unsigned) (N_DATADDR(*execp));
167         data_len_ = unsigned(execp->a_data / sizeof(Word));
168
169         struct nlist* syms   = (struct nlist *)
170           &ptr[unsigned(N_SYMOFF(*execp)+nodeFileOffset_)];
171         unsigned      nsyms  = execp->a_syms / sizeof(struct nlist);
172         char*         strs   = &ptr[unsigned(N_STROFF(*execp)+nodeFileOffset_)];
173         string        module = "DEFAULT_MODULE";
174         string        name   = "DEFAULT_SYMBOL";
175
176         vector<Symbol> allsymbols;
177
178         for (unsigned i = 0; i < nsyms; i++) {
179             unsigned char sstab = syms[i].n_type & (N_TYPE | N_STAB);
180
181             Symbol::SymbolLinkage linkage =
182                 ((syms[i].n_type & N_EXT)
183                     ? Symbol::SL_GLOBAL
184                     : Symbol::SL_LOCAL);
185             Symbol::SymbolType type = Symbol::PDST_UNKNOWN;
186             bool st_kludge = false;
187
188             switch (sstab) {
189             // we do not want header files to become modules
190             // case N_BINCL:
191             // case N_SOL:
192
193             case N_FN:
194             case N_SO:
195                 {
196                 module = string(&strs[syms[i].n_un.n_strx]);
197                 type   = Symbol::PDST_MODULE;
198                 break;
199                 }
200
201             case N_BSS:
202             case N_DATA:
203                 {
204                 type = Symbol::PDST_OBJECT;
205                 break;
206                 }
207             case N_TEXT:
208                 {
209                 // KLUDGE: <file>.o entries have a nasty habit of showing up in
210                 // symbol tables as N_TEXT when debugging info is not
211                 // in the symbol table
212                 int len = strlen(&strs[syms[i].n_un.n_strx]);
213                 type = Symbol::PDST_OBJECT;
214                 if ((len > 2) &&
215                     ((&strs[syms[i].n_un.n_strx])[len-2] == '.') &&
216                     (linkage == Symbol::SL_LOCAL) &&
217                     (!(0x3 & syms[i].n_value))) {
218                   type = Symbol::PDST_MODULE;
219                   st_kludge = true;
220                   break;
221                 } else if (linkage != Symbol::SL_GLOBAL) {
222                   break;
223                 } else if (0x3 & syms[i].n_value) {
224                   break;
225                 } else {
226                   // this may be a function
227                   st_kludge = true;
228                 }
229                 break;
230                 }
231
232             case N_FNAME:
233             case N_FUN:
234                 {
235                 type = Symbol::PDST_FUNCTION;
236                 break;
237                 }
238
239             case N_SLINE:
240                 // process line numbers here, when we know how to
241
242             default:
243                 continue;
244             }
245
246             name = string(&strs[syms[i].n_un.n_strx]);
247             allsymbols += Symbol(name, module, type, linkage,
248                                  syms[i].n_value, st_kludge);
249
250         }
251           // Sort the symbols on address to find the function boundaries
252           allsymbols.sort(symbol_compare);
253
254           unsigned nsymbols = allsymbols.size();
255           for (unsigned u = 0; u < nsymbols; u++) {
256             unsigned v = u+1;
257             while (v < nsymbols && allsymbols[v].addr() == allsymbols[u].addr())
258               v++;
259             unsigned size = 0;
260             if (v < nsymbols)
261               size = (unsigned)allsymbols[v].addr() - (unsigned)allsymbols[u].addr();
262
263             symbols_[allsymbols[u].name()] =
264                Symbol(allsymbols[u].name(), allsymbols[u].module(),
265                       allsymbols[u].type(), allsymbols[u].linkage(),
266                       allsymbols[u].addr(), allsymbols[u].kludge(),
267                       size);
268            }      
269
270
271     }
272
273     /* catch */
274 cleanup: {
275         if (did_open && (close(fd) == -1)) {
276             log_perror(err_func_, "close");
277         }
278     }
279 }
280
281
282 \f
283
284 inline
285 Object::Object(const string file, void (*err_func)(const char *))
286     : AObject(file, err_func), nodeFileOffset_(0) {
287     load_object();
288 }
289
290 inline
291 Object::Object(const Object& obj)
292     : AObject(obj), nodeFileOffset_(0) {
293     load_object();
294 }
295
296 inline
297 Object::~Object() {
298 }
299
300 inline
301 Object&
302 Object::operator=(const Object& obj) {
303     (void) AObject::operator=(obj);
304     nodeFileOffset_ = obj.nodeFileOffset_;
305     return *this;
306 }
307
308 #endif /* !defined(_Object_bsd_h_) */