6bb2cde4ce8bbdf0faf26ae1a3ca18a9b54e3e79
[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       int size;
182       fscanf(gf, "%s\n", &name, &size);
183       _namelist.push_back(strdup(name));
184     }
185     fclose(gf);
186     loaded = 1;
187 }
188
189
190 /**
191    Analyze the current set of global variables, determine 
192    which are user globals and which are system globals, 
193    and store the list of user globals. 
194  */
195 CtgGlobalList::CtgGlobalList() {
196     datalen=0;
197     nRec=0;
198     
199     int count;
200     int relt_size = 0;
201     int symt_size = 0;
202     int type, symindx;
203     char *sym_name;
204     ELFXX_TYPE_Rel *relt=NULL;       //Relocation table
205     ELFXX_TYPE_Sym *symt=NULL;       //symbol table
206     char *str_tab=NULL;         //String table
207
208     for (count = 0; count < _namelist.size(); count ++) 
209     {
210         unsigned long addr;
211         int size;
212         if (0 > lookup_obj_sym(_namelist[count], &addr, &size)) {
213                 fprintf(stderr, "%s: no such symbol\n", _namelist[count]);
214                 continue;
215         }
216         void *ptr = (void *)addr;
217         int gSize = ALIGN8(size);
218                     
219 //#if DEBUG_GOT_MANAGER
220             printf("   -> %s is a user global, of size %d, at %p\n",
221               _namelist[count], size, ptr);
222 //#endif
223                     
224         rec.push_back(CtgRec(ptr,datalen,size));
225         datalen+=gSize;
226     }
227
228     nRec=rec.size();
229     
230 #if DEBUG_GOT_MANAGER   
231     printf("relt has %d entries, %d of which are user globals\n\n", 
232         relt_size,nRec);
233 #endif
234 }
235
236 /****************** Global Variable Storage and Swapping *********************/
237 CpvStaticDeclare(CtgGlobals,_curCtg);
238
239 struct CtgGlobalStruct {
240 public:
241     /* This is set when our data is pointed to by the current GOT */
242     int installed;
243     int inited;
244
245     /* Pointer to our global data segment. */
246     void *data_seg;  
247     int seg_size; /* size in bytes of data segment */
248     
249     void allocate(int size) {
250       seg_size=size;
251         /* global data segment need to be isomalloc */
252       if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
253         data_seg=CmiIsomalloc(seg_size);
254       else
255         data_seg=malloc(seg_size);
256       inited = 0;
257     }
258     
259     CtgGlobalStruct(void) {
260       installed=0;
261       data_seg=0;
262     }
263     ~CtgGlobalStruct() {
264       if (data_seg) {
265         free(data_seg);
266       }
267     }
268     
269     void pup(PUP::er &p);
270 };
271
272 void CtgGlobalStruct::pup(PUP::er &p) {
273     p | seg_size;
274         /* global data segment need to be isomalloc pupped */
275     if (CmiMemoryIs(CMI_MEMORY_IS_ISOMALLOC))
276       CmiIsomallocPup(&p, &data_seg);
277     else {
278       if (p.isUnpacking()) allocate(seg_size);
279       p((char *)data_seg, seg_size);
280     }
281 }
282
283 /// Singleton object describing our global variables:
284 static CtgGlobalList *_ctgList=NULL;
285 /// Singleton object describing the original values for the globals.
286 static CtgGlobalStruct *_ctgListGlobals=NULL;
287
288 extern "C" int init_symtab(char *exename);
289
290 /** Initialize the globals support (called on each processor). */
291 void CtgInit(void) {
292         CpvInitialize(int, CmiPICMethod);
293         CpvAccess(CmiPICMethod) = 2;
294         CpvInitialize(CtgGlobal,_curCtg);
295         
296         if (!_ctgList) 
297         {
298         /*
299           First call on this node: parse out our globals:
300         */
301                 readGlobals();
302                 init_symtab(CkGetArgv()[0]);
303
304                 CtgGlobalList *l=new CtgGlobalList;
305                 CtgGlobalStruct *g=new CtgGlobalStruct;
306                 if (CmiMyNode()==0) {
307                         CmiPrintf("CHARM> -copyglobals enabled\n");
308                 }
309                 
310                 g->allocate(l->getSize());
311                 l->read(g->data_seg);
312                 l->install(g->data_seg);
313                 _ctgList=l;
314                 _ctgListGlobals=g;
315         }
316         /* CmiNodeAllBarrier();  no smp anyway */
317         
318         CpvAccess(_curCtg)=_ctgListGlobals;
319 }
320
321 /** Copy the current globals into this new set */
322 CtgGlobals CtgCreate(void) {
323         CtgGlobalStruct *g=new CtgGlobalStruct;
324         g->allocate(_ctgList->getSize());
325         _ctgList->read(g->data_seg);
326         return g;
327 }
328
329 /** PUP this (not currently installed) globals set */
330 CtgGlobals CtgPup(pup_er pv, CtgGlobals g) {
331         PUP::er *p=(PUP::er *)pv;
332         if (p->isUnpacking()) g=new CtgGlobalStruct;
333         if (g->installed) 
334                 CmiAbort("CtgPup called on currently installed globals!\n");
335         g->pup(*p);
336         if (g->seg_size!=_ctgList->getSize())
337                 CmiAbort("CtgPup: global variable size changed during migration!\n");
338         return g;
339 }
340
341 /** Install this set of globals. If g==NULL, returns to original globals. */
342 void CtgInstall(CtgGlobals g) {
343         CtgGlobals *cur=&CpvAccess(_curCtg);
344         CtgGlobals oldG=*cur;
345         if (g==NULL) g=_ctgListGlobals;
346         if (g == oldG) return;
347         if (oldG) {
348           _ctgList->read(oldG->data_seg);             /* store globals to own copy */
349         }
350         *cur=g;
351         oldG->installed=0;
352         _ctgList->install(g->data_seg);
353         g->installed=1;
354 }
355
356 /** Delete this (not currently installed) set of globals. */
357 void CtgFree(CtgGlobals g) {
358         if (g->installed) CmiAbort("CtgFree called on currently installed globals!\n");
359         delete g;
360 }
361
362 CtgGlobals CtgCurrentGlobals(void){
363         return CpvAccess(_curCtg);
364 }
365
366 void CtgInstall_var(CtgGlobals g, void *ptr) {
367         CtgGlobals *cur=&CpvAccess(_curCtg);
368         CtgGlobals oldG = *cur;
369         if (oldG)
370         _ctgList->read_var(oldG->data_seg, ptr);
371         _ctgList->install_var(g->data_seg, ptr);             /* store globals to own copy */
372 }
373
374 void CtgUninstall_var(CtgGlobals g, void *ptr) {
375         CtgGlobals *cur=&CpvAccess(_curCtg);
376         CtgGlobals oldG = *cur;
377         if (oldG)
378         _ctgList->read_var(g->data_seg, ptr);             /* store globals to own copy */
379         _ctgList->install_var(oldG->data_seg, ptr);             /* store globals to own copy */
380 }
381
382 #else     /* no ELF */
383
384 #include "global-nop.c"
385
386 #endif