Drop an extra unused argument to fscanf
[charm.git] / src / conv-core / global-elfcopy.C
1 /*  Library to manage the program's global and static varaibles manually
2  *  by copying them during context switch.
3  *
4  *
5  *  Developed by Gengbin Zheng (gzheng@uiuc.edu) 12/06
6  *
7  */
8
9 #include "converse.h"
10 #include "cklists.h"
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <strings.h>
15 #include <errno.h>
16
17 #include "charm.h"
18 #include "pup.h"
19
20 #if CMK_HAS_ELF_H
21 #include <elf.h>
22
23 #define DEBUG_GOT_MANAGER 0
24
25 #if !CMK_SHARED_VARS_UNAVAILABLE
26 #  error "Global-elfcopy won't work properly under smp version: -copyglobals disabled"
27 #endif
28
29 CpvDeclare(int, CmiPICMethod);
30
31 #if CMK_AMD64 || CMK_CRAYXT
32 typedef Elf64_Addr    ELFXX_TYPE_Addr;
33 typedef Elf64_Dyn     ELFXX_TYPE_Dyn;
34 typedef Elf64_Rela    ELFXX_TYPE_Rel;
35 typedef Elf64_Sym     ELFXX_TYPE_Sym;
36 #define ELFXX_R_TYPE   ELF64_R_TYPE
37 #define ELFXX_R_SYM    ELF64_R_SYM
38 #define ELFXX_ST_TYPE  ELF64_ST_TYPE
39 #define CMK_DT_REL     DT_RELA
40 #define CMK_DT_RELSZ   DT_RELASZ
41 #define is_elf_global(x)  ((x) == R_X86_64_GLOB_DAT)
42 #elif CMK_IA64
43 #error "NOT SUPPORTED"
44 #else
45 typedef Elf32_Addr    ELFXX_TYPE_Addr;
46 typedef Elf32_Dyn     ELFXX_TYPE_Dyn;
47 typedef Elf32_Rel     ELFXX_TYPE_Rel;
48 typedef Elf32_Sym     ELFXX_TYPE_Sym;
49 #define ELFXX_R_TYPE   ELF32_R_TYPE
50 #define ELFXX_R_SYM    ELF32_R_SYM
51 #define ELFXX_ST_TYPE  ELF32_ST_TYPE
52 #define CMK_DT_REL     DT_REL
53 #define CMK_DT_RELSZ   DT_RELSZ
54 #define is_elf_global(x)  ((x) == R_386_GLOB_DAT)
55 #endif
56
57 extern ELFXX_TYPE_Dyn _DYNAMIC[];      //The Dynamic section table pointer
58
59 /****************** Global Variable Understanding *********************/
60 /**
61  Keeps a list of global variables.
62 */
63 class CtgGlobalList
64 {
65   int datalen; ///< Number of bytes in the table of global data.
66   struct CtgRec {
67     void *got; ///< Points to our entry in the GOT.
68     int off; ///< Our byte offset into the table of global data.
69     int size;
70     CtgRec() {got=NULL;}
71     CtgRec(void *got_,int off_,int size_) :got(got_), off(off_), size(size_) {}
72   };
73   CkVec<CtgRec> rec;
74   int nRec;
75 public:
76   /**
77    Analyze the current set of global variables, determine 
78    which are user globals and which are system globals, 
79    and store the list of user globals. 
80   */
81   CtgGlobalList();
82   
83   /// Return the number of bytes needed to store our global data.
84   inline int getSize(void) const {return datalen;}
85   
86   /// Copy the current set of global data into this set,
87   ///   which must be getSize() bytes.
88   void read(void *datav) const;
89   
90   /// copy data to globals
91   inline void install(void *datav) const {
92     char *data=(char *)datav;
93     for (int i=0;i<nRec;i++) {
94       int size;
95       if (i<nRec-1) 
96         size=rec[i+1].off-rec[i].off;
97       else /* i==nRec-1, last one: */ 
98         size=datalen-rec[i].off;
99       memcpy((void *)rec[i].got, data+rec[i].off, rec[i].size);
100     }
101   }
102   
103   inline void install_var(void *datav, void *ptr) const {
104     char *data=(char *)datav;
105     int done = 0;
106     for (int i=0;i<nRec;i++) {
107       long offset = (char*)ptr-(char *)rec[i].got;
108       if (offset >= 0 && offset < rec[i].size) {
109         memcpy((void *)rec[i].got, data+rec[i].off, rec[i].size);
110         done = 1;
111         break;
112       }
113     }
114   }
115
116   void read_var(void *datav, void *ptr) const;
117   
118 private:
119   /* Return 1 if this is the name of a user global variable;
120      0 if this is the name of some other (Charm or system)
121      global variable. */
122   int isUserSymbol(const char *name);
123 };
124
125 int CtgGlobalList::isUserSymbol(const char *name) {
126     // return 1;
127     if((strncmp("_", name, 1) == 0) || (strncmp("Cpv_", name, 4) == 0)
128        || (strncmp("Csv_", name, 4) == 0) || (strncmp("Ctv_", name, 4) == 0)
129        || (strncmp("Bnv_", name, 4) == 0) || (strncmp("Bpv_", name, 4) == 0)
130        || (strncmp("ckout", name, 5) == 0) || (strncmp("stdout", name, 6) == 0)
131        || (strncmp("environ", name, 7) == 0)
132        || (strncmp("stderr", name, 6) == 0) || (strncmp("stdin", name, 5) == 0))
133         return 0;
134     
135     return 1;
136 }
137
138 void CtgGlobalList::read(void *datav) const {
139     char *data=(char *)datav;
140     for (int i=0;i<nRec;i++) {
141       int size;
142       if (i<nRec-1) 
143         size=rec[i+1].off-rec[i].off;
144       else /* i==nRec-1, last one: */ 
145         size=datalen-rec[i].off;
146       memcpy(data+rec[i].off, (void *)rec[i].got, rec[i].size);
147     }
148 }
149
150 void CtgGlobalList::read_var(void *datav, void *ptr) const {
151     char *data=(char *)datav;
152     int done = 0;
153     for (int i=0;i<nRec;i++) {
154       long offset = (char*)ptr-(char *)rec[i].got;
155       if (offset >= 0 && offset < rec[i].size) {
156         memcpy(data+rec[i].off, (void *)rec[i].got, rec[i].size);
157         done = 1;
158         break;
159       }
160     }
161 }
162
163 CkVec<char *>  _namelist;
164 static int loaded = 0;
165
166 extern "C" int lookup_obj_sym(char *name, unsigned long *val, int *size);
167
168 // read from a file called "globals"
169 static void readGlobals()
170 {
171     if (loaded) return;
172     const char *fname = "globals";
173 printf("Loading globals from file \"%s\" ... \n", fname);
174     FILE *gf = fopen(fname, "r");
175     if (gf == NULL) {
176       CmiAbort("Failed to load globals, file may not exist!");
177     }
178     while (!feof(gf)) 
179     {
180       char name[1024];
181       fscanf(gf, "%s\n", &name);
182       _namelist.push_back(strdup(name));
183     }
184     fclose(gf);
185     loaded = 1;
186 }
187
188
189 /**
190    Analyze the current set of global variables, determine 
191    which are user globals and which are system globals, 
192    and store the list of user globals. 
193  */
194 CtgGlobalList::CtgGlobalList() {
195     datalen=0;
196     nRec=0;
197     
198     int count;
199     int relt_size = 0;
200     int symt_size = 0;
201     int type, symindx;
202     char *sym_name;
203     ELFXX_TYPE_Rel *relt=NULL;       //Relocation table
204     ELFXX_TYPE_Sym *symt=NULL;       //symbol table
205     char *str_tab=NULL;         //String table
206
207     for (count = 0; count < _namelist.size(); count ++) 
208     {
209         unsigned long addr;
210         int size;
211         if (0 > lookup_obj_sym(_namelist[count], &addr, &size)) {
212                 fprintf(stderr, "%s: no such symbol\n", _namelist[count]);
213                 continue;
214         }
215         void *ptr = (void *)addr;
216         int gSize = ALIGN8(size);
217                     
218 //#if DEBUG_GOT_MANAGER
219             printf("   -> %s is a user global, of size %d, at %p\n",
220               _namelist[count], size, ptr);
221 //#endif
222                     
223         rec.push_back(CtgRec(ptr,datalen,size));
224         datalen+=gSize;
225     }
226
227     nRec=rec.size();
228     
229 #if DEBUG_GOT_MANAGER   
230     printf("relt has %d entries, %d of which are user globals\n\n", 
231         relt_size,nRec);
232 #endif
233 }
234
235 /****************** Global Variable Storage and Swapping *********************/
236 CpvStaticDeclare(CtgGlobals,_curCtg);
237
238 struct CtgGlobalStruct {
239 public:
240     /* This is set when our data is pointed to by the current GOT */
241     int installed;
242     int inited;
243
244     /* Pointer to our global data segment. */
245     void *data_seg;  
246     int seg_size; /* size in bytes of data segment */
247     
248     void allocate(int size) {
249       seg_size=size;
250         /* global data segment need to be isomalloc */
251       if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
252         data_seg=CmiIsomalloc(seg_size);
253       else
254         data_seg=malloc(seg_size);
255       inited = 0;
256     }
257     
258     CtgGlobalStruct(void) {
259       installed=0;
260       data_seg=0;
261     }
262     ~CtgGlobalStruct() {
263       if (data_seg) {
264         free(data_seg);
265       }
266     }
267     
268     void pup(PUP::er &p);
269 };
270
271 void CtgGlobalStruct::pup(PUP::er &p) {
272     p | seg_size;
273         /* global data segment need to be isomalloc pupped */
274     if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
275       CmiIsomallocPup(&p, &data_seg);
276     else {
277       if (p.isUnpacking()) allocate(seg_size);
278       p((char *)data_seg, seg_size);
279     }
280 }
281
282 /// Singleton object describing our global variables:
283 static CtgGlobalList *_ctgList=NULL;
284 /// Singleton object describing the original values for the globals.
285 static CtgGlobalStruct *_ctgListGlobals=NULL;
286
287 extern "C" int init_symtab(char *exename);
288
289 /** Initialize the globals support (called on each processor). */
290 void CtgInit(void) {
291         CpvInitialize(int, CmiPICMethod);
292         CpvAccess(CmiPICMethod) = 2;
293         CpvInitialize(CtgGlobal,_curCtg);
294         
295         if (!_ctgList) 
296         {
297         /*
298           First call on this node: parse out our globals:
299         */
300                 readGlobals();
301                 init_symtab(CkGetArgv()[0]);
302
303                 CtgGlobalList *l=new CtgGlobalList;
304                 CtgGlobalStruct *g=new CtgGlobalStruct;
305                 if (CmiMyNode()==0) {
306                         CmiPrintf("CHARM> -copyglobals enabled\n");
307                 }
308                 
309                 g->allocate(l->getSize());
310                 l->read(g->data_seg);
311                 l->install(g->data_seg);
312                 _ctgList=l;
313                 _ctgListGlobals=g;
314         }
315         /* CmiNodeAllBarrier();  no smp anyway */
316         
317         CpvAccess(_curCtg)=_ctgListGlobals;
318 }
319
320 /** Copy the current globals into this new set */
321 CtgGlobals CtgCreate(void) {
322         CtgGlobalStruct *g=new CtgGlobalStruct;
323         g->allocate(_ctgList->getSize());
324         _ctgList->read(g->data_seg);
325         return g;
326 }
327
328 /** PUP this (not currently installed) globals set */
329 CtgGlobals CtgPup(pup_er pv, CtgGlobals g) {
330         PUP::er *p=(PUP::er *)pv;
331         if (p->isUnpacking()) g=new CtgGlobalStruct;
332         if (g->installed) 
333                 CmiAbort("CtgPup called on currently installed globals!\n");
334         g->pup(*p);
335         if (g->seg_size!=_ctgList->getSize())
336                 CmiAbort("CtgPup: global variable size changed during migration!\n");
337         return g;
338 }
339
340 /** Install this set of globals. If g==NULL, returns to original globals. */
341 void CtgInstall(CtgGlobals g) {
342         CtgGlobals *cur=&CpvAccess(_curCtg);
343         CtgGlobals oldG=*cur;
344         if (g==NULL) g=_ctgListGlobals;
345         if (g == oldG) return;
346         if (oldG) {
347           _ctgList->read(oldG->data_seg);             /* store globals to own copy */
348         }
349         *cur=g;
350         oldG->installed=0;
351         _ctgList->install(g->data_seg);
352         g->installed=1;
353 }
354
355 /** Delete this (not currently installed) set of globals. */
356 void CtgFree(CtgGlobals g) {
357         if (g->installed) CmiAbort("CtgFree called on currently installed globals!\n");
358         delete g;
359 }
360
361 CtgGlobals CtgCurrentGlobals(void){
362         return CpvAccess(_curCtg);
363 }
364
365 void CtgInstall_var(CtgGlobals g, void *ptr) {
366         CtgGlobals *cur=&CpvAccess(_curCtg);
367         CtgGlobals oldG = *cur;
368         if (oldG)
369         _ctgList->read_var(oldG->data_seg, ptr);
370         _ctgList->install_var(g->data_seg, ptr);             /* store globals to own copy */
371 }
372
373 void CtgUninstall_var(CtgGlobals g, void *ptr) {
374         CtgGlobals *cur=&CpvAccess(_curCtg);
375         CtgGlobals oldG = *cur;
376         if (oldG)
377         _ctgList->read_var(g->data_seg, ptr);             /* store globals to own copy */
378         _ctgList->install_var(oldG->data_seg, ptr);             /* store globals to own copy */
379 }
380
381 #else     /* no ELF */
382
383 #include "global-nop.c"
384
385 #endif