char *GmfReadByteFlow(int64_t MshIdx, int *NmbByt)
{
   int         cod, *WrdTab;
   size_t      i, NmbWrd;
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;

   // Read and allocate the number of 4-byte words in the byteflow
   if(!(NmbWrd = GmfStatKwd(MshIdx, GmfByteFlow)))
      return(NULL);

   if(!(WrdTab = malloc(NmbWrd * WrdSiz)))
      return(NULL);

   // Disable the endianess conversion
   cod = msh->cod;
   msh->cod = 1;

   // Read the exact number of bytes in the byteflow
   GmfGotoKwd(MshIdx, GmfByteFlow);
   GmfGetLin(MshIdx, GmfByteFlow, NmbByt);

   // Read the byteflow as 4-byte blocks
   for(i=0;i<NmbWrd;i++)
      GmfGetLin(MshIdx, GmfByteFlow, &WrdTab[i]);

   // Enable endianess convertion
   msh->cod = cod;

   return((char *)WrdTab);
}


Removed a potential buffer overflow crash in GmfOpenMesh and debugged the test_libmeshb_block_pipeline.f that crashed

static void SetPos(GmfMshSct *msh, int64_t pos)
{
   int IntVal;

   if(msh->ver >= 3)
      RecDblWrd(msh, (unsigned char*)&pos);
   else
   {
      IntVal = (int)pos;
      RecWrd(msh, (unsigned char*)&IntVal);
   }
}

A buffer overflow in the GmfOpenMesh() function of libMeshb v7.61 allows attackers to cause a Denial of Service (DoS) via a crafted MESH file.


static int64_t GetFilPos(GmfMshSct *msh)
{
#ifdef WITH_GMF_AIO
   if(msh->typ & Bin)
      return(lseek(msh->FilDes, 0, 1));
   else
      return(MYFTELL(msh->hdl));
#else
   return(MYFTELL(msh->hdl));
#endif
}


int GmfGetFloatPrecision(int64_t MshIdx)
{
   int FltSiz;
   GmfMshSct *msh = (GmfMshSct *)MshIdx;

   if(GmfStatKwd(MshIdx, GmfFloatingPointPrecision))
   {
      GmfGotoKwd(MshIdx, GmfFloatingPointPrecision);
      GmfGetLin(MshIdx, GmfFloatingPointPrecision, &FltSiz);

      if(FltSiz == 32 || FltSiz == 64)
         msh->FltSiz = FltSiz;
   }

   return(msh->FltSiz);
}


int NAMF77(GmfSetBlock, gmfsetblock)(  TYPF77(int64_t) MshIdx,
                                       TYPF77(int)     KwdCod,
                                       TYPF77(int64_t) BegIdx,
                                       TYPF77(int64_t) EndIdx,
                                       TYPF77(int)     MapTyp,
                                       void           *MapTab,
                                       void           *prc, ... )
{
   char        *UsrDat[ GmfMaxTyp ], *UsrBas[ GmfMaxTyp ];
   char        *StrTab[5] = { "", "%.9g", "%.17g", "%d", "%lld" }, *FilPos;
   char        *FilBuf = NULL, *FrtBuf = NULL, *BckBuf = NULL;
   char        **BegTab, **EndTab, *BegUsrDat, *EndUsrDat;
   int         i, j, *FilPtrI32, *UsrPtrI32, FilTyp[ GmfMaxTyp ];
   int         UsrTyp[ GmfMaxTyp ], TypSiz[5] = {0,4,8,4,8};
   int         err, *IntMapTab = NULL, typ, mod = GmfArgLst;
   int         *TypTab, *SizTab, IniFlg = 1, TotSiz = 0, VecCnt, ArgCnt = 0;
   float       *FilPtrR32, *UsrPtrR32;
   double      *FilPtrR64, *UsrPtrR64;
   int64_t     UsrNmbLin, BlkNmbLin = 0, BlkBegIdx, BlkEndIdx = 0;
   int64_t     *FilPtrI64, *UsrPtrI64, *LngMapTab = NULL, OldIdx = 0;
   size_t      FilBegIdx = VALF77(BegIdx), FilEndIdx = VALF77(EndIdx);
   void        (*UsrPrc)(int64_t, int64_t, void *) = NULL;
   size_t      UsrLen[ GmfMaxTyp ], ret, LinSiz, VecLen, s, b, NmbBlk;
   va_list     VarArg;
   GmfMshSct   *msh = (GmfMshSct *) VALF77(MshIdx);
   KwdSct      *kwd = &msh->KwdTab[ VALF77(KwdCod) ];
   struct      aiocb aio;
#ifdef F77API
   int         NmbArg = 0;
   void        *ArgTab[ MaxArg ];
#else
   char        *UsrArg = NULL;
#endif

   // Save the current stack environment for longjmp
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      if(FilBuf)
         free(FilBuf);

      return(0);
   }

   // Check mesh and keyword
   if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) || !kwd->NmbLin )
      return(0);

   // Make sure it's not a simple information keyword
   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Temporarily overwright the given begin and end values
   // as arbitrary position block write is not yet implemented
   FilBegIdx = 1;
   FilEndIdx = kwd->NmbLin;

   // Check user's bounds
   if( (FilBegIdx < 1) || (FilBegIdx > FilEndIdx) || (FilEndIdx > (size_t)kwd->NmbLin) )
      return(0);

   // Compute the number of lines to be written
   UsrNmbLin = FilEndIdx - FilBegIdx + 1;

   // Get the renumbering map if any
   if(VALF77(MapTyp) == GmfInt)
      IntMapTab = (int *)MapTab;
   else if(VALF77(MapTyp) == GmfLong)
      LngMapTab = (int64_t *)MapTab;

   // Start decoding the arguments
   va_start(VarArg, prc);
   LinSiz = 0;

   // Get the user's postprocessing procedure and argument adresses, if any
#ifdef F77API
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      NmbArg = *(va_arg(VarArg, int *));

      for(i=0;i<NmbArg;i++)
         ArgTab[i] = va_arg(VarArg, void *);
   }
#else
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      UsrArg = va_arg(VarArg, void *);
   }
#endif

   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Read the first data type to select between list and table mode
   typ = VALF77(va_arg(VarArg, TYPF77(int)));

   // If the table mode is selected, read the four additional tables
   // containing the arguments: type, vector size, begin and end pointers
   if(typ == GmfArgTab)
   {
      mod = GmfArgTab;
      TypTab = va_arg(VarArg, int *);
      SizTab = va_arg(VarArg, int *);
      BegTab = va_arg(VarArg, char **);
      EndTab = va_arg(VarArg, char **);
   }

   // Read the arguments until to total size reaches the keyword's size
   while(TotSiz < kwd->SolSiz)
   {
      // In list mode all arguments are read from the variable argument buffer
      if(mod == GmfArgLst)
      {
         // Do not read the type argument for the first iteration because
         // it was read befeore the loop begins to get the argument mode
         if(IniFlg)
            IniFlg = 0;
         else
            typ = VALF77(va_arg(VarArg, TYPF77(int)));

         // In case the type is a vector. get its size and change the type
         // for the corresponding scalar type
         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = VALF77(va_arg(VarArg, TYPF77(int)));
         }
         else
            VecCnt = 1;

         BegUsrDat = va_arg(VarArg, char *);
         EndUsrDat = va_arg(VarArg, char *);
      }
      else
      {
         // Do exactly the same as above but the arguments are read from
         // the tables instead of VarArgs
         typ = TypTab[ ArgCnt ];

         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = SizTab[ ArgCnt ];
         }
         else
            VecCnt = 1;

         BegUsrDat = (char *)BegTab[ ArgCnt ];
         EndUsrDat = (char *)EndTab[ ArgCnt ];
         ArgCnt++;
      }

      if(UsrNmbLin > 1)
         VecLen = (size_t)(EndUsrDat - BegUsrDat) / (UsrNmbLin - 1);
      else
         VecLen = 0;

      // Compute the consecutive begin / end adresses for vector data types
      for(i=0;i<VecCnt;i++)
      {
         UsrTyp[ TotSiz ]  = typ;
         UsrBas[ TotSiz ]  = BegUsrDat + i * TypSiz[ typ ];
         UsrDat[ TotSiz ]  = UsrBas[ TotSiz ];
         UsrLen[ TotSiz ]  = VecLen;
         TotSiz++;
      }
   }

   // Get the file's data type
   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
         if(msh->FltSiz == 32)
            FilTyp[i] = GmfFloat;
         else
            FilTyp[i] = GmfDouble;
      else
         if(msh->ver <= 3)
            FilTyp[i] = GmfInt;
         else
            FilTyp[i] = GmfLong;

      // Compute the file stride
      LinSiz += TypSiz[ FilTyp[i] ];
   }

   va_end(VarArg);

   // Write the whole kwd data
   if(msh->typ & Asc)
   {
      if(UsrPrc)
#ifdef F77API
         CalF77Prc(1, kwd->NmbLin, UsrPrc, NmbArg, ArgTab);
#else
         UsrPrc(1, kwd->NmbLin, UsrArg);
#endif

      for(s=FilBegIdx; s<=FilEndIdx; s++)
         for(j=0;j<kwd->SolSiz;j++)
         {
            if(UsrTyp[j] == GmfFloat)
            {
               UsrPtrR32 = (float *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], (double)*UsrPtrR32);
            }
            else if(UsrTyp[j] == GmfDouble)
            {
               UsrPtrR64 = (double *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrR64);
            }
            else if(UsrTyp[j] == GmfInt)
            {
               UsrPtrI32 = (int *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrI32);
            }
            else if(UsrTyp[j] == GmfLong)
            {
               UsrPtrI64 = (int64_t *)UsrDat[j];
               fprintf(msh->hdl, StrTab[ UsrTyp[j] ], *UsrPtrI64);
            }

            if(j < kwd->SolSiz -1)
               fprintf(msh->hdl, " ");
            else
               fprintf(msh->hdl, "\n");

            //UsrDat[j] += UsrLen[j];
            if(IntMapTab)
               UsrDat[j] = UsrBas[j] + IntMapTab[s] * UsrLen[j];
            else if(LngMapTab)
               UsrDat[j] = UsrBas[j] + LngMapTab[s] * UsrLen[j];
            else
               UsrDat[j] = UsrBas[j] + s * UsrLen[j];
         }
   }
   else
   {
      // Allocate the front and back buffers
      if(!(BckBuf = malloc(BufSiz * LinSiz)))
         return(0);

      if(!(FrtBuf = malloc(BufSiz * LinSiz)))
         return(0);

      // Setup the asynchronous parameters
      memset(&aio, 0, sizeof(struct aiocb));
      FilBuf = BckBuf;
#ifdef WITH_GMF_AIO
      aio.aio_fildes = msh->FilDes;
#else
      aio.aio_fildes = msh->hdl;
#endif
      aio.aio_offset = (off_t)GetFilPos(msh);

      NmbBlk = UsrNmbLin / BufSiz;

      // Loop over N+1 blocks
      for(b=0;b<=NmbBlk+1;b++)
      {
         // Launch an asynchronous block write
         // except for the first loop iteration
         if(b)
         {
            aio.aio_nbytes = BlkNmbLin * LinSiz;

            if(my_aio_write(&aio) == -1)
            {
#ifdef WITH_GMF_AIO
               printf("aio_fildes = %d\n",aio.aio_fildes);
#else
               printf("aio_fildes = %p\n",aio.aio_fildes);
#endif
               printf("aio_buf    = %p\n",aio.aio_buf);
               printf("aio_offset = " INT64_T_FMT "\n",(int64_t)aio.aio_offset);
               printf("aio_nbytes = " INT64_T_FMT "\n",(int64_t)aio.aio_nbytes);
               printf("errno      = %d\n",errno);
               exit(1);
            }
         }

         // Parse the block data except at the last loop iteration
         if(b<=NmbBlk)
         {
            // The last block is shorter
            if(b == NmbBlk)
               BlkNmbLin = UsrNmbLin - b * BufSiz;
            else
               BlkNmbLin = BufSiz;

            FilPos = FilBuf;
            BlkBegIdx = BlkEndIdx+1;
            BlkEndIdx += BlkNmbLin;

            // Call user's preprocessing first
            if(UsrPrc)
#ifdef F77API
               CalF77Prc(BlkBegIdx, BlkEndIdx, UsrPrc, NmbArg, ArgTab);
#else
               UsrPrc(BlkBegIdx, BlkEndIdx, UsrArg);
#endif

            // Then copy it's data to the file buffer
            for(i=0;i<BlkNmbLin;i++)
            {
               OldIdx++;

               for(j=0;j<kwd->SolSiz;j++)
               {
                  if(IntMapTab)
                     UsrDat[j] = UsrBas[j] + (IntMapTab[ OldIdx ] - 1) * UsrLen[j];
                  else if(LngMapTab)
                     UsrDat[j] = UsrBas[j] + (LngMapTab[ OldIdx ] - 1) * UsrLen[j];
                  else
                     UsrDat[j] = UsrBas[j] + (OldIdx - 1) * UsrLen[j];

                  if(FilTyp[j] == GmfInt)
                  {
                     FilPtrI32 = (int *)FilPos;

                     if(UsrTyp[j] == GmfInt)
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *FilPtrI32 = *UsrPtrI32;
                     }
                     else
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *FilPtrI32 = (int)*UsrPtrI64;
                     }
                  }
                  else if(FilTyp[j] == GmfLong)
                  {
                     FilPtrI64 = (int64_t *)FilPos;

                     if(UsrTyp[j] == GmfLong)
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *FilPtrI64 = *UsrPtrI64;
                     }
                     else
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *FilPtrI64 = (int64_t)*UsrPtrI32;
                     }
                  }
                  else if(FilTyp[j] == GmfFloat)
                  {
                     FilPtrR32 = (float *)FilPos;

                     if(UsrTyp[j] == GmfFloat)
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *FilPtrR32 = *UsrPtrR32;
                     }
                     else
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *FilPtrR32 = (float)*UsrPtrR64;
                     }
                  }
                  else if(FilTyp[j] == GmfDouble)
                  {
                     FilPtrR64 = (double *)FilPos;

                     if(UsrTyp[j] == GmfDouble)
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *FilPtrR64 = *UsrPtrR64;
                     }
                     else
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *FilPtrR64 = (double)*UsrPtrR32;
                     }
                  }

                  FilPos += TypSiz[ FilTyp[j] ];
               }
            }
         }

         // Wait for write completion execpt at the first loop iteration
         if(b)
         {
            while(my_aio_error(&aio) == EINPROGRESS);

            err = my_aio_error(&aio);
            ret = my_aio_return(&aio);

            if (err != 0) {
              printf (" Error at aio_error() : %s\n", strerror (err));
              exit(1);
            }

            if (ret != aio.aio_nbytes) {
              printf(" Error at aio_return()\n");
              exit(1);
            }

            // Move the write position
            aio.aio_offset += (off_t)aio.aio_nbytes;
         }

         // Swap the buffers
         if(FilBuf == BckBuf)
         {
            aio.aio_buf = BckBuf;
            FilBuf = FrtBuf;
         }
         else
         {
            aio.aio_buf = FrtBuf;
            FilBuf = BckBuf;
         }
      }

      SetFilPos(msh, aio.aio_offset);
      free(BckBuf);
      free(FrtBuf);
   }

   return(1);
}


int APIF77(gmfsetkwd)(  int64_t *MshIdx, int *KwdIdx, int *NmbLin,
                        int *NmbTyp, int *TypTab, int *deg, int *NmbNod)
{
   if(!strcmp(GmfKwdFmt[ *KwdIdx ][2], "hr"))
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin, *NmbTyp, TypTab, *deg, *NmbNod));
   else if(!strcmp(GmfKwdFmt[ *KwdIdx ][2], "sr"))
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin, *NmbTyp, TypTab));
   else
      return(GmfSetKwd(*MshIdx, *KwdIdx, *NmbLin));
}


size_t my_aio_return(struct aiocb *aiocbp)
{
   return(aiocbp->aio_nbytes);
}


int my_aio_error(const struct aiocb *aiocbp)
{
   return(aiocbp->aio_lio_opcode);
}


int GmfCloseMesh(int64_t MshIdx)
{
   int i, res = 1;
   GmfMshSct *msh = (GmfMshSct *)MshIdx;

   RecBlk(msh, msh->buf, 0);

   // In write down the "End" kw in write mode
   if(msh->mod == GmfWrite)
   {
      if(msh->typ & Asc)
         fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]);
      else
         GmfSetKwd(MshIdx, GmfEnd, 0);
   }

   // Close the file and free the mesh structure
   if(msh->typ & Bin)
#ifdef WITH_GMF_AIO
      close(msh->FilDes);
#else
      fclose(msh->hdl);
#endif
   else if(fclose(msh->hdl))
      res = 0;

   // Free optional H.O. renumbering tables
   for(i=0;i<GmfLastKeyword;i++)
      if(msh->KwdTab[i].OrdTab)
         free(msh->KwdTab[i].OrdTab);

   free(msh);

   return(res);
}


static void ScaKwdHdr(GmfMshSct *msh, int KwdCod)
{
   int      i;
   KwdSct   *kwd = &msh->KwdTab[ KwdCod ];

   if(!strcmp("i", GmfKwdFmt[ KwdCod ][1]))
      if(msh->typ & Asc)
         safe_fscanf(msh->hdl, INT64_T_FMT, &kwd->NmbLin, msh->err);
      else
         if(msh->ver <= 3)
         {
            ScaWrd(msh, (unsigned char *)&i);
            kwd->NmbLin = i;
         }
         else
            ScaDblWrd(msh, (unsigned char *)&kwd->NmbLin);
   else
      kwd->NmbLin = 1;

   if(!strcmp("sr", GmfKwdFmt[ KwdCod ][2])
   || !strcmp("hr", GmfKwdFmt[ KwdCod ][2]) )
   {
      if(msh->typ & Asc)
      {
         safe_fscanf(msh->hdl, "%d", &kwd->NmbTyp, msh->err);

         for(i=0;i<kwd->NmbTyp;i++)
            safe_fscanf(msh->hdl, "%d", &kwd->TypTab[i], msh->err);

         // Scan two extra fields for HO solutions: deg and nmb Nodes
         if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]))
         {
            safe_fscanf(msh->hdl, "%d", &kwd->deg, msh->err);
            safe_fscanf(msh->hdl, "%d", &kwd->NmbNod, msh->err);
         }
         else
         {
            kwd->deg = 0;
            kwd->NmbNod = 1;
         }

      }
      else
      {
         ScaWrd(msh, (unsigned char *)&kwd->NmbTyp);

         for(i=0;i<kwd->NmbTyp;i++)
            ScaWrd(msh, (unsigned char *)&kwd->TypTab[i]);

         // Scan two extra fields for HO solutions: deg and nmb Nodes
         if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]))
         {
            ScaWrd(msh, (unsigned char *)&kwd->deg);
            ScaWrd(msh, (unsigned char *)&kwd->NmbNod);
         }
         else
         {
            kwd->deg = 0;
            kwd->NmbNod = 1;
         }
      }
   }

   ExpFmt(msh, KwdCod);
   kwd->pos = GetFilPos(msh);
}


int APIF77(gmfgotokwd)(int64_t *MshIdx, int *KwdIdx)
{
   return(GmfGotoKwd(*MshIdx, *KwdIdx));
}


int64_t APIF77(gmfopenmesh)(  char *FilNam, int *mod,
                              int *ver, int *dim, int StrSiz )
{
   int   i = 0;
   char  TmpNam[ GmfStrSiz ];

   if(StrSiz <= 0)
      return(0);

   // Trim trailing spaces from the fortran string
   while(isspace(FilNam[ StrSiz-1 ]))
      StrSiz--;

   for(i=0;i<StrSiz;i++)
      TmpNam[i] = FilNam[i];

   TmpNam[ StrSiz ] = 0;

   if(*mod == GmfRead)
      return(GmfOpenMesh(TmpNam, *mod, ver, dim));
   else
      return(GmfOpenMesh(TmpNam, *mod, *ver, *dim));
}


static int ScaKwdTab(GmfMshSct *msh)
{
   int      KwdCod, c;
   int64_t  NexPos, EndPos, LstPos;
   char     str[ GmfStrSiz ];

   if(msh->typ & Asc)
   {
      // Scan each string in the file until the end
      while(fscanf(msh->hdl, "%100s", str) != EOF)
      {
         // Fast test in order to reject quickly the numeric values
         if(isalpha(str[0]))
         {
            // Search which kwd code this string is associated with, then get its
            // header and save the curent position in file (just before the data)
            for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++)
               if(!strcmp(str, GmfKwdFmt[ KwdCod ][0]))
               {
                  ScaKwdHdr(msh, KwdCod);
                  break;
               }
         }
         else if(str[0] == '#')
            while((c = fgetc(msh->hdl)) != '\n' && c != EOF);
      }
   }
   else
   {
      // Get file size
      EndPos = GetFilSiz(msh);
      LstPos = -1;

      // Jump through kwd positions in the file
      do
      {
         // Get the kwd code and the next kwd position
         ScaWrd(msh, ( char *)&KwdCod);
         NexPos = GetPos(msh);

         // Make sure the flow does not move beyond the file size
         if(NexPos > EndPos)
            longjmp(msh->err, -24);

         // And check that it does not move back
         if(NexPos && (NexPos <= LstPos))
            longjmp(msh->err, -30);

         LstPos = NexPos;

         // Check if this kwd belongs to this mesh version
         if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) )
            ScaKwdHdr(msh, KwdCod);

         // Go to the next kwd
         if(NexPos && !(SetFilPos(msh, NexPos)))
            longjmp(msh->err, -25);

      }while(NexPos && (KwdCod != GmfEnd));
   }

   return(1);
}


int    my_aio_read  (      struct aiocb *aiocbp){return(aio_read  (aiocbp));}


static void ExpFmt(GmfMshSct *msh, int KwdCod)
{
   int         i, j, TmpSiz=0, IntWrd, FltWrd;
   char        chr;
   const char  *InpFmt = GmfKwdFmt[ KwdCod ][2];
   KwdSct      *kwd = &msh->KwdTab[ KwdCod ];

   // Set the kwd's type
   if(!strlen(GmfKwdFmt[ KwdCod ][1]))
      kwd->typ = InfKwd;
   else if( !strcmp(InpFmt, "sr") || !strcmp(InpFmt, "hr") )
      kwd->typ = SolKwd;
   else
      kwd->typ = RegKwd;

   // Get the solution-field's size
   if(kwd->typ == SolKwd)
      for(i=0;i<kwd->NmbTyp;i++)
         switch(kwd->TypTab[i])
         {
            case GmfSca    : TmpSiz += 1; break;
            case GmfVec    : TmpSiz += msh->dim; break;
            case GmfSymMat : TmpSiz += (msh->dim * (msh->dim+1)) / 2; break;
            case GmfMat    : TmpSiz += msh->dim * msh->dim; break;
         }

   // Scan each character from the format string
   i = kwd->SolSiz = kwd->NmbWrd = 0;

   while(i < (int)strlen(InpFmt))
   {
      chr = InpFmt[ i++ ];

      if(chr == 'd')
      {
         chr = InpFmt[i++];

         for(j=0;j<msh->dim;j++)
            kwd->fmt[ kwd->SolSiz++ ] = chr;
      }
      else if((chr == 's')||(chr == 'h'))
      {
         chr = InpFmt[i++];

         for(j=0;j<TmpSiz;j++)
            kwd->fmt[ kwd->SolSiz++ ] = chr;
      }
      else
         kwd->fmt[ kwd->SolSiz++ ] = chr;
   }

   if(msh->FltSiz == 32)
      FltWrd = 1;
   else
      FltWrd = 2;

   if(msh->ver <= 3)
      IntWrd = 1;
   else
      IntWrd = 2;

   for(i=0;i<kwd->SolSiz;i++)
      switch(kwd->fmt[i])
      {
         case 'i' : kwd->NmbWrd += IntWrd; break;
         case 'c' : kwd->NmbWrd += FilStrSiz; break;
         case 'r' : kwd->NmbWrd += FltWrd;break;
      }

   // HO solution: duplicate the format as many times as the number of nodes
   if( !strcmp(InpFmt, "hr") && (kwd->NmbNod > 1) )
   {
      for(i=1;i<=kwd->NmbNod;i++)
         for(j=0;j<kwd->SolSiz;j++)
            kwd->fmt[ i * kwd->SolSiz + j ] = kwd->fmt[j];

      kwd->SolSiz *= kwd->NmbNod;
      kwd->NmbWrd *= kwd->NmbNod;
   }
}


int my_aio_write(struct aiocb *aiocbp)
{
   if( (MYFSEEK(aiocbp->aio_fildes, (off_t)aiocbp->aio_offset, SEEK_SET) == 0)
   &&  (fwrite(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes)
       == aiocbp->aio_nbytes) )
   {
      aiocbp->aio_lio_opcode = 0;
   }
   else
   {
      aiocbp->aio_lio_opcode = -1;
   }

   return(aiocbp->aio_lio_opcode);
}


int NAMF77(GmfGetBlock, gmfgetblock)(  TYPF77(int64_t) MshIdx,
                                       TYPF77(int)     KwdCod,
                                       TYPF77(int64_t) BegIdx,
                                       TYPF77(int64_t) EndIdx,
                                       TYPF77(int)     MapTyp,
                                       void           *MapTab,
                                       void           *prc, ... )
{
   char        *UsrDat[ GmfMaxTyp ], *UsrBas[ GmfMaxTyp ], *FilPos, *EndUsrDat;
   char        *FilBuf = NULL, *FrtBuf = NULL, *BckBuf = NULL, *BegUsrDat;
   char        *StrTab[5] = { "", "%f", "%lf", "%d", INT64_T_FMT };
   char        **BegTab, **EndTab;
   int         i, j, k, *FilPtrI32, *UsrPtrI32, FilTyp[ GmfMaxTyp ];
   int         UsrTyp[ GmfMaxTyp ], TypSiz[5] = {0,4,8,4,8};
   int         *IntMapTab = NULL, err, TotSiz = 0, IniFlg = 1, mod = GmfArgLst;
   int         *TypTab, *SizTab, typ, VecCnt, ArgCnt = 0;
   float       *FilPtrR32, *UsrPtrR32;
   double      *FilPtrR64, *UsrPtrR64;
   int64_t     BlkNmbLin, *FilPtrI64, *UsrPtrI64, BlkBegIdx, BlkEndIdx = 0;
   int64_t     *LngMapTab = NULL, OldIdx = 0, UsrNmbLin, VecLen;
   size_t      FilBegIdx = VALF77(BegIdx), FilEndIdx = VALF77(EndIdx);
   void        (*UsrPrc)(int64_t, int64_t, void *) = NULL;
   size_t      UsrLen[ GmfMaxTyp ], ret, LinSiz, b, NmbBlk;
   va_list     VarArg;
   GmfMshSct   *msh = (GmfMshSct *) VALF77(MshIdx);
   KwdSct      *kwd = &msh->KwdTab[ VALF77(KwdCod) ];
   struct      aiocb aio;
#ifdef F77API
   int         NmbArg = 0;
   void        *ArgTab[ MaxArg ];
#else
   char        *UsrArg = NULL;
#endif

   // Save the current stack environment for longjmp
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      if(BckBuf)
         free(BckBuf);

      if(FrtBuf)
         free(FrtBuf);

      return(0);
   }

   // Check mesh and keyword
   if( (VALF77(KwdCod) < 1) || (VALF77(KwdCod) > GmfMaxKwd) || !kwd->NmbLin )
      return(0);

   // Make sure it's not a simple information keyword
   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Check user's bounds
   if( (FilBegIdx < 1) || (FilBegIdx > FilEndIdx) || (FilEndIdx > (size_t)kwd->NmbLin) )
      return(0);

   // Compute the number of lines to be read
   UsrNmbLin = FilEndIdx - FilBegIdx + 1;

   // Get the renumbering map if any
   if(VALF77(MapTyp) == GmfInt)
      IntMapTab = (int *)MapTab;
   else if(VALF77(MapTyp) == GmfLong)
      LngMapTab = (int64_t *)MapTab;

   // Start decoding the arguments
   va_start(VarArg, prc);
   LinSiz = 0;

   // Get the user's preprocessing procedure and argument adresses, if any
#ifdef F77API
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      NmbArg = *(va_arg(VarArg, int *));

      for(i=0;i<NmbArg;i++)
         ArgTab[i] = va_arg(VarArg, void *);
   }
#else
   if(prc)
   {
      UsrPrc = (void (*)(int64_t, int64_t, void *))prc;
      UsrArg = va_arg(VarArg, void *);
   }
#endif

   if( (kwd->typ != RegKwd) && (kwd->typ != SolKwd) )
      return(0);

   // Read the first data type to select between list and table mode
   typ = VALF77(va_arg(VarArg, TYPF77(int)));

   // If the table mode is selected, read the four additional tables
   // containing the arguments: type, vector size, begin and end pointers
   if(typ == GmfArgTab)
   {
      mod = GmfArgTab;
      TypTab = va_arg(VarArg, int *);
      SizTab = va_arg(VarArg, int *);
      BegTab = va_arg(VarArg, char **);
      EndTab = va_arg(VarArg, char **);
   }

   // Read the arguments until to total size reaches the keyword's size
   while(TotSiz < kwd->SolSiz)
   {
      // In list mode all arguments are read from the variable argument buffer
      if(mod == GmfArgLst)
      {
         // Do not read the type argument for the first iteration because
         // it was read befeore the loop begins to get the argument mode
         if(IniFlg)
            IniFlg = 0;
         else
            typ = VALF77(va_arg(VarArg, TYPF77(int)));

         // In case the type is a vector. get its size and change the type
         // for the corresponding scalar type
         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = VALF77(va_arg(VarArg, TYPF77(int)));
         }
         else
            VecCnt = 1;

         BegUsrDat = va_arg(VarArg, char *);
         EndUsrDat = va_arg(VarArg, char *);
      }
      else
      {
         // Do exactly the same as above but the arguments are read from
         // the tables instead of VarArgs
         typ = TypTab[ ArgCnt ];

         if(typ >= GmfFloatVec && typ <= GmfLongVec)
         {
            typ -= 4;
            VecCnt = SizTab[ ArgCnt ];
         }
         else
            VecCnt = 1;

         BegUsrDat = (char *)BegTab[ ArgCnt ];
         EndUsrDat = (char *)EndTab[ ArgCnt ];
         ArgCnt++;
      }

      if(UsrNmbLin > 1)
         VecLen = (size_t)(EndUsrDat - BegUsrDat) / (UsrNmbLin - 1);
      else
         VecLen = 0;

      // Compute the consecutive begin / end adresses for vector data types
      for(i=0;i<VecCnt;i++)
      {
         UsrTyp[ TotSiz ]  = typ;
         UsrBas[ TotSiz ]  = BegUsrDat + i * TypSiz[ typ ];
         UsrDat[ TotSiz ]  = UsrBas[ TotSiz ];
         UsrLen[ TotSiz ]  = VecLen;
         TotSiz++;
      }
   }

   // Get the file's data type
   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
         if(msh->FltSiz == 32)
            FilTyp[i] = GmfFloat;
         else
            FilTyp[i] = GmfDouble;
      else
         if(msh->ver <= 3)
            FilTyp[i] = GmfInt;
         else
            FilTyp[i] = GmfLong;

      // Compute the file stride
      LinSiz += TypSiz[ FilTyp[i] ];
   }

   va_end(VarArg);

   // Move file pointer to the keyword data
   SetFilPos(msh, kwd->pos);

   // Read the whole kwd data
   if(msh->typ & Asc)
   {
      OldIdx = 1;

      for(i=1;i<=FilEndIdx;i++)
      {
         for(j=0;j<kwd->SolSiz;j++)
         {
            // Reorder HO nodes on the fly
            if(kwd->OrdTab && (j != kwd->SolSiz-1))
               k = kwd->OrdTab[j];
            else
               k = j;

            // Move to the next user's data line only when the desired
            // begining position in the ascii file has been reached since
            // we cannot move directly to an arbitrary position
            if(IntMapTab)
               UsrDat[j] = UsrBas[k] + (IntMapTab[ OldIdx ] - 1) * UsrLen[k];
            else if(LngMapTab)
               UsrDat[j] = UsrBas[k] + (LngMapTab[ OldIdx ] - 1) * UsrLen[k];
            else
               UsrDat[j] = UsrBas[k] + (OldIdx - 1) * UsrLen[k];

            safe_fscanf(msh->hdl, StrTab[ UsrTyp[j] ], UsrDat[j], msh->err);
         }

         if(i >= FilBegIdx)
            OldIdx++;

         // Call the user's preprocessing procedure
         if(UsrPrc)
#ifdef F77API
            CalF77Prc(1, kwd->NmbLin, UsrPrc, NmbArg, ArgTab);
#else
            UsrPrc(1, kwd->NmbLin, UsrArg);
#endif
      }
   }
   else
   {
      // Allocate both front and back buffers
      if(!(BckBuf = malloc(BufSiz * LinSiz)))
         return(0);

      if(!(FrtBuf = malloc(BufSiz * LinSiz)))
         return(0);

      // Setup the ansynchonous parameters
      memset(&aio, 0, sizeof(struct aiocb));
      FilBuf = BckBuf;
      aio.aio_buf = BckBuf;
#ifdef WITH_GMF_AIO
      aio.aio_fildes = msh->FilDes;
#else
      aio.aio_fildes = msh->hdl;
#endif
      aio.aio_offset = (off_t)(GetFilPos(msh) + (FilBegIdx-1) * LinSiz);

      NmbBlk = UsrNmbLin / BufSiz;

      // Loop over N+1 blocks
      for(b=0;b<=NmbBlk+1;b++)
      {
         // Wait for the previous block read to complete except
         // for the first loop interation
         if(b)
         {
            while(my_aio_error(&aio) == EINPROGRESS);

            err = my_aio_error(&aio);
            ret = my_aio_return(&aio);

            if (err != 0) {
              printf (" Error at aio_error() : %s\n", strerror (err));
              exit(1);
            }

            if (ret != aio.aio_nbytes) {
              printf(" Error at aio_return()\n");
              exit(1);
            }

            // Increment the reading position
            aio.aio_offset += (off_t)aio.aio_nbytes;

            // and swap the buffers
            if(aio.aio_buf == BckBuf)
            {
               aio.aio_buf = FrtBuf;
               FilBuf = BckBuf;
            }
            else
            {
               aio.aio_buf = BckBuf;
               FilBuf = FrtBuf;
            }
         }

         // Read a chunk of data except for the last loop interarion
         if(b <= NmbBlk)
         {
            // The last block is shorter than the others
            if(b == NmbBlk)
               BlkNmbLin = UsrNmbLin - b * BufSiz;
            else
               BlkNmbLin = BufSiz;

            aio.aio_nbytes = BlkNmbLin * LinSiz;

            if(my_aio_read(&aio) == -1)
            {
               printf("block      = %zd / %zd\n", b+1, NmbBlk+1);
               printf("size       = "INT64_T_FMT" lines\n", BlkNmbLin);
#ifdef WITH_GMF_AIO
               printf("aio_fildes = %d\n",aio.aio_fildes);
#else
               printf("aio_fildes = %p\n",aio.aio_fildes);
#endif
               printf("aio_buf    = %p\n",aio.aio_buf);
               printf("aio_offset = " INT64_T_FMT "\n",(int64_t)aio.aio_offset);
               printf("aio_nbytes = " INT64_T_FMT "\n",(int64_t)aio.aio_nbytes);
               printf("errno      = %d\n",errno);
               exit(1);
            }
         }

         // Then decode the block and store it in the user's data structure
         // except for the first loop interation
         if(b)
         {
            // The last block is shorter than the others
            if(b-1 == NmbBlk)
               BlkNmbLin = UsrNmbLin - (b-1) * BufSiz;
            else
               BlkNmbLin = BufSiz;

            BlkBegIdx = BlkEndIdx+1;
            BlkEndIdx += BlkNmbLin;
            FilPos = FilBuf;

            for(i=0;i<BlkNmbLin;i++)
            {
               OldIdx++;

               for(j=0;j<kwd->SolSiz;j++)
               {
                  if(msh->cod != 1)
                     SwpWrd(FilPos, TypSiz[ FilTyp[j] ]);

                  // Reorder HO nodes on the fly
                  if(kwd->OrdTab && (j != kwd->SolSiz-1))
                     k = kwd->OrdTab[j];
                  else
                     k = j;

                  if(IntMapTab)
                     UsrDat[j] = UsrBas[k] + (IntMapTab[ OldIdx ] - 1) * UsrLen[k];
                  else if(LngMapTab)
                     UsrDat[j] = UsrBas[k] + (LngMapTab[ OldIdx ] - 1) * UsrLen[k];
                  else
                     UsrDat[j] = UsrBas[k] + (OldIdx - 1) * UsrLen[k];

                  if(FilTyp[j] == GmfInt)
                  {
                     FilPtrI32 = (int *)FilPos;

                     if(UsrTyp[j] == GmfInt)
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *UsrPtrI32 = *FilPtrI32;
                     }
                     else
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *UsrPtrI64 = (int64_t)*FilPtrI32;
                     }
                  }
                  else if(FilTyp[j] == GmfLong)
                  {
                     FilPtrI64 = (int64_t *)FilPos;

                     if(UsrTyp[j] == GmfLong)
                     {
                        UsrPtrI64 = (int64_t *)UsrDat[j];
                        *UsrPtrI64 = *FilPtrI64;
                     }
                     else
                     {
                        UsrPtrI32 = (int *)UsrDat[j];
                        *UsrPtrI32 = (int)*FilPtrI64;
                     }
                  }
                  else if(FilTyp[j] == GmfFloat)
                  {
                     FilPtrR32 = (float *)FilPos;

                     if(UsrTyp[j] == GmfFloat)
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *UsrPtrR32 = *FilPtrR32;
                     }
                     else
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *UsrPtrR64 = (double)*FilPtrR32;
                     }
                  }
                  else if(FilTyp[j] == GmfDouble)
                  {
                     FilPtrR64 = (double *)FilPos;

                     if(UsrTyp[j] == GmfDouble)
                     {
                        UsrPtrR64 = (double *)UsrDat[j];
                        *UsrPtrR64 = *FilPtrR64;
                     }
                     else
                     {
                        UsrPtrR32 = (float *)UsrDat[j];
                        *UsrPtrR32 = (float)*FilPtrR64;
                     }
                  }

                  FilPos += TypSiz[ FilTyp[j] ];
               }
            }

            // Call the user's preprocessing procedure
            if(UsrPrc)
#ifdef F77API
               CalF77Prc(BlkBegIdx, BlkEndIdx, UsrPrc, NmbArg, ArgTab);
#else
               UsrPrc(BlkBegIdx, BlkEndIdx, UsrArg);
#endif
         }
      }

      free(BckBuf);
      free(FrtBuf);
   }

   return(1);
}


static void CalF77Prc(  int64_t BegIdx, int64_t EndIdx,
                        void *prc, int NmbArg, void **ArgTab )
{
   switch(NmbArg)
   {
      case 1 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 1)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 1)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 1));
      }break;

      case 2 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 2)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 2)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 2));
      }break;

      case 3 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 3)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 3)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 3));
      }break;

      case 4 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 4)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 4)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 4));
      }break;

      case 5 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 5)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 5)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 5));
      }break;

      case 6 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 6)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 6)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 6));
      }break;

      case 7 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 7)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 7)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 7));
      }break;

      case 8 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 8)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 8)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 8));
      }break;

      case 9 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 9)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 9)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 9));
      }break;

      case 10 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 10)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 10)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 10));
      }break;

      case 11 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 11)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 11)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 11));
      }break;

      case 12 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 12)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 12)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 12));
      }break;

      case 13 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 13)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 13)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 13));
      }break;

      case 14 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 14)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 14)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 14));
      }break;

      case 15 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 15)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 15)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 15));
      }break;

      case 16 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 16)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 16)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 16));
      }break;

      case 17 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 17)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 17)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 17));
      }break;

      case 18 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 18)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 18)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 18));
      }break;

      case 19 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 19)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 19)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 19));
      }break;

      case 20 :
      {
         void (*prc1)(int64_t *, int64_t *, DUP(void *, 20)) =
            (void (*)(int64_t *, int64_t *, DUP(void *, 20)))prc;
         prc1(&BegIdx, &EndIdx, ARG(ArgTab, 20));
      }break;
   }
}


static void ScaWrd(GmfMshSct *msh, void *ptr)
{
#ifdef WITH_GMF_AIO
   if(read(msh->FilDes, ptr, WrdSiz) != WrdSiz)
#else
   if(fread(ptr, WrdSiz, 1, msh->hdl) != 1)
#endif
      longjmp(msh->err, -26);

   if(msh->cod != 1)
      SwpWrd((char *)ptr, WrdSiz);
}


int NAMF77(GmfSetLin, gmfsetlin)(TYPF77(int64_t) MshIdx, TYPF77(int) KwdCod, ...)
{
   int         i, pos, *IntBuf, err;
   int64_t     *LngBuf;
   float       *FltSolTab, *FltBuf;
   double      *DblSolTab, *DblBuf;
   va_list     VarArg;
   GmfMshSct   *msh = (GmfMshSct *) VALF77(MshIdx);
   KwdSct      *kwd = &msh->KwdTab[ VALF77(KwdCod) ];

   if( ( VALF77(KwdCod) < 1) || ( VALF77(KwdCod) > GmfMaxKwd) )
      return(0);

   // Save the current stack environment for longjmp
   // This is needed in RecBlk()
   if( (err = setjmp(msh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", msh, err);
#endif
      return(0);
   }

   // Start decoding the arguments
   va_start(VarArg, KwdCod);

   if(kwd->typ != SolKwd)
   {
      if(msh->typ & Asc)
      {
         for(i=0;i<kwd->SolSiz;i++)
         {
            if(kwd->fmt[i] == 'r')
            {
               if(msh->FltSiz == 32)
#ifdef F77API
                  fprintf(msh->hdl, "%.9g ", *(va_arg(VarArg, float *)));
#else
                  fprintf(msh->hdl, "%.9g ", va_arg(VarArg, double));
#endif
               else
                  fprintf(msh->hdl, "%.17g ", VALF77(va_arg(VarArg, TYPF77(double))));
            }
            else if(kwd->fmt[i] == 'i')
            {
               if(msh->ver <= 3)
                  fprintf(msh->hdl, "%d ", VALF77(va_arg(VarArg, TYPF77(int))));
               else
               {
                  // [Bruno] %ld -> INT64_T_FMT
                  fprintf( msh->hdl, INT64_T_FMT " ",
                           VALF77(va_arg(VarArg, TYPF77(int64_t))));
               }
            }
            else if(kwd->fmt[i] == 'c')
               fprintf(msh->hdl, "%s ", va_arg(VarArg, char *));
         }
      }
      else
      {
         pos = 0;

         for(i=0;i<kwd->SolSiz;i++)
         {
            if(kwd->fmt[i] == 'r')
            {
               if(msh->FltSiz == 32)
               {
                  FltBuf = (void *)&msh->buf[ pos ];
#ifdef F77API
                  *FltBuf = (float)*(va_arg(VarArg, float *));
#else
                  *FltBuf = (float)va_arg(VarArg, double);
#endif
                  pos += 4;
               }
               else
               {
                  DblBuf = (void *)&msh->buf[ pos ];
                  *DblBuf = VALF77(va_arg(VarArg, TYPF77(double)));
                  pos += 8;
               }
            }
            else if(kwd->fmt[i] == 'i')
            {
               if(msh->ver <= 3)
               {
                  IntBuf = (void *)&msh->buf[ pos ];
                  *IntBuf = VALF77(va_arg(VarArg, TYPF77(int)));
                  pos += 4;
               }
               else
               {
                  LngBuf = (void *)&msh->buf[ pos ];
                  *LngBuf = VALF77(va_arg(VarArg, TYPF77(int64_t)));
                  pos += 8;
               }
            }
            else if(kwd->fmt[i] == 'c')
            {
               memset(&msh->buf[ pos ], 0, FilStrSiz * WrdSiz);
               strncpy(&msh->buf[ pos ], va_arg(VarArg, char *), FilStrSiz * WrdSiz);
               pos += FilStrSiz;
            }
         }

         RecBlk(msh, msh->buf, kwd->NmbWrd);
      }
   }
   else
   {
      if(msh->FltSiz == 32)
      {
         FltSolTab = va_arg(VarArg, float *);

         if(msh->typ & Asc)
            for(i=0; i<kwd->SolSiz; i++)
               fprintf(msh->hdl, "%.9g ", (double)FltSolTab[i]);
         else
            RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd);
      }
      else
      {
         DblSolTab = va_arg(VarArg, double *);

         if(msh->typ & Asc)
            for(i=0; i<kwd->SolSiz; i++)
               fprintf(msh->hdl, "%.17g ", DblSolTab[i]);
         else
            RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd);
      }
   }

   va_end(VarArg);

   if(msh->typ & Asc)
      fprintf(msh->hdl, "\n");

   return(1);
}


int GmfCpyLin(int64_t InpIdx, int64_t OutIdx, int KwdCod)
{
   char        s[ WrdSiz * FilStrSiz ];
   double      d;
   float       f;
   int         i, a, err;
   int64_t     l;
   GmfMshSct   *InpMsh = (GmfMshSct *)InpIdx, *OutMsh = (GmfMshSct *)OutIdx;
   KwdSct      *kwd = &InpMsh->KwdTab[ KwdCod ];

   // Save the current stack environment for longjmp
   if( (err = setjmp(InpMsh->err)) != 0)
   {
#ifdef GMFDEBUG
      printf("libMeshb : mesh %p : error %d\n", InpMsh, err);
#endif
      return(0);
   }

   for(i=0;i<kwd->SolSiz;i++)
   {
      if(kwd->fmt[i] == 'r')
      {
         if(InpMsh->FltSiz == 32)
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%f", &f, InpMsh->err);
            else
               ScaWrd(InpMsh, (unsigned char *)&f);

            d = (double)f;
         }
         else
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%lf", &d, InpMsh->err);
            else
               ScaDblWrd(InpMsh, (unsigned char *)&d);

            f = (float)d;
         }

         if(OutMsh->FltSiz == 32)
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%.9g ", (double)f);
            else
               RecWrd(OutMsh, (unsigned char *)&f);
         else
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%.17g ", d);
            else
               RecDblWrd(OutMsh, (unsigned char *)&d);
      }
      else if(kwd->fmt[i] == 'i')
      {
         if(InpMsh->ver <= 3)
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, "%d", &a, InpMsh->err);
            else
               ScaWrd(InpMsh, (unsigned char *)&a);

            l = (int64_t)a;
         }
         else
         {
            if(InpMsh->typ & Asc)
               safe_fscanf(InpMsh->hdl, INT64_T_FMT, &l, InpMsh->err);
            else
               ScaDblWrd(InpMsh, (unsigned char *)&l);

            a = (int)l;
         }

         if( (i == kwd->SolSiz-1) && (a > GmfMaxRefTab[ KwdCod ]) )
            GmfMaxRefTab[ KwdCod ] = a;

         if(OutMsh->ver <= 3)
         {
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, "%d ", a);
            else
               RecWrd(OutMsh, (unsigned char *)&a);
         }
         else
         {
            if(OutMsh->typ & Asc)
               fprintf(OutMsh->hdl, INT64_T_FMT" ", l);
            else
               RecDblWrd(OutMsh, (unsigned char *)&l);
         }
      }
      else if(kwd->fmt[i] == 'c')
      {
         memset(s, 0, FilStrSiz * WrdSiz);

         if(InpMsh->typ & Asc)
            safe_fgets(s, WrdSiz * FilStrSiz, InpMsh->hdl, InpMsh->err);
         else
#ifdef WITH_GMF_AIO
            read(InpMsh->FilDes, s, WrdSiz * FilStrSiz);
#else
            safe_fread(s, WrdSiz, FilStrSiz, InpMsh->hdl, InpMsh->err);
#endif
         if(OutMsh->typ & Asc)
            fprintf(OutMsh->hdl, "%s ", s);
         else
#ifdef WITH_GMF_AIO
            write(OutMsh->FilDes, s, WrdSiz * FilStrSiz);
#else
            fwrite(s, WrdSiz, FilStrSiz, OutMsh->hdl);
#endif
      }
   }

   if(OutMsh->typ & Asc)
      fprintf(OutMsh->hdl, "\n");

   return(1);
}


int64_t GmfStatKwd(int64_t MshIdx, int KwdCod, ...)
{
   int         i, *PtrNmbTyp, *PtrSolSiz, *TypTab, *PtrDeg, *PtrNmbNod;
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;
   KwdSct      *kwd;
   va_list     VarArg;

   if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
      return(0);

   kwd = &msh->KwdTab[ KwdCod ];

   if(!kwd->NmbLin)
      return(0);

   // Read further arguments if this kw is a sol
   if(kwd->typ == SolKwd)
   {
      va_start(VarArg, KwdCod);

      PtrNmbTyp = va_arg(VarArg, int *);
      *PtrNmbTyp = kwd->NmbTyp;

      PtrSolSiz = va_arg(VarArg, int *);
      *PtrSolSiz = kwd->SolSiz;

      TypTab = va_arg(VarArg, int *);

      for(i=0;i<kwd->NmbTyp;i++)
         TypTab[i] = kwd->TypTab[i];

      // Add two extra paramaters for HO elements: degree and nmb nodes
      if(!strcmp("hr", GmfKwdFmt[ KwdCod ][2]) )
      {
         PtrDeg = va_arg(VarArg, int *);
         *PtrDeg = kwd->deg;

         PtrNmbNod = va_arg(VarArg, int *);
         *PtrNmbNod = kwd->NmbNod;
      }

      va_end(VarArg);
   }

   return(kwd->NmbLin);
}


int GmfSetHONodesOrdering(int64_t MshIdx, int KwdCod, int *BasTab, int *OrdTab)
{
   int i, j, k, flg, NmbNod, NmbCrd;
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;
   KwdSct      *kwd;

   // printf("\n\tGmfSetHONodesOrdering 0\n");

   if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
      return(0);

   kwd = &msh->KwdTab[ KwdCod ];

   // Find the Bezier indices dimension according to the element's kind
   switch(KwdCod)
   {
      case GmfEdges   :          NmbNod =  2; NmbCrd = 1; break;
      case GmfEdgesP2 :          NmbNod =  3; NmbCrd = 1; break;
      case GmfEdgesP3 :          NmbNod =  4; NmbCrd = 1; break;
      case GmfEdgesP4 :          NmbNod =  5; NmbCrd = 1; break;
      case GmfTriangles   :      NmbNod =  3; NmbCrd = 3; break;
      case GmfTrianglesP2 :      NmbNod =  6; NmbCrd = 3; break;
      case GmfTrianglesP3 :      NmbNod = 10; NmbCrd = 3; break;
      case GmfTrianglesP4 :      NmbNod = 15; NmbCrd = 3; break;
      case GmfQuadrilaterals   : NmbNod =  4; NmbCrd = 2; break;
      case GmfQuadrilateralsQ2 : NmbNod =  9; NmbCrd = 2; break;
      case GmfQuadrilateralsQ3 : NmbNod = 16; NmbCrd = 2; break;
      case GmfQuadrilateralsQ4 : NmbNod = 25; NmbCrd = 2; break;
      case GmfTetrahedra   :     NmbNod =  4; NmbCrd = 4; break;
      case GmfTetrahedraP2 :     NmbNod = 10; NmbCrd = 4; break;
      case GmfTetrahedraP3 :     NmbNod = 20; NmbCrd = 4; break;
      case GmfTetrahedraP4 :     NmbNod = 35; NmbCrd = 4; break;
      case GmfPyramids   :       NmbNod =  5; NmbCrd = 3; break;
      case GmfPyramidsP2 :       NmbNod = 14; NmbCrd = 3; break;
      case GmfPyramidsP3 :       NmbNod = 30; NmbCrd = 3; break;
      case GmfPyramidsP4 :       NmbNod = 55; NmbCrd = 3; break;
      case GmfPrisms   :         NmbNod =  6; NmbCrd = 4; break;
      case GmfPrismsP2 :         NmbNod = 18; NmbCrd = 4; break;
      case GmfPrismsP3 :         NmbNod = 40; NmbCrd = 4; break;
      case GmfPrismsP4 :         NmbNod = 75; NmbCrd = 4; break;
      case GmfHexahedra   :      NmbNod =  8; NmbCrd = 3; break;
      case GmfHexahedraQ2 :      NmbNod = 27; NmbCrd = 3; break;
      case GmfHexahedraQ3 :      NmbNod = 64; NmbCrd = 3; break;
      case GmfHexahedraQ4 :      NmbNod =125; NmbCrd = 3; break;
      default : return(0);
   }

   // Free and rebuild the mapping table if there were already one
   if(kwd->OrdTab)
      free(kwd->OrdTab);

   if(!(kwd->OrdTab = malloc(NmbNod * sizeof(int))))
      return(0);

   // Find the corresponding Bezier coordinates from the source table
   for(i=0;i<NmbNod;i++)
   {
      for(j=0;j<NmbNod;j++)
      {
         flg = 1;

         for(k=0;k<NmbCrd;k++)
            if(BasTab[ i * NmbCrd + k ] != OrdTab[ j * NmbCrd + k ])
            {
               flg = 0;
               break;
            }

         if(flg)
            kwd->OrdTab[j] = i;
      }
   }

   // Check the ordering consistency
   for(i=0;i<NmbNod;i++)
   {
      flg = 0;

      for(j=0;j<NmbNod;j++)
         if(kwd->OrdTab[j] == i)
         {
            flg = 1;
            break;
         }

      if(!flg)
      {
         for(j=0;j<NmbNod;j++)
            kwd->OrdTab[j] = j;

         return(0);
      }
   }

   return(1);
}


static void RecDblWrd(GmfMshSct *msh, const void *wrd)
{
   // [Bruno] added error control
#ifdef WITH_GMF_AIO
   if(write(msh->FilDes, wrd, WrdSiz * 2) != WrdSiz*2)
#else
   if(fwrite(wrd, WrdSiz, 2, msh->hdl) != 2)
#endif
      longjmp(msh->err,-29);
}


static void ScaDblWrd(GmfMshSct *msh, void *ptr)
{
#ifdef WITH_GMF_AIO
   if(read(msh->FilDes, ptr, WrdSiz * 2) != WrdSiz * 2)
#else
   if( fread(ptr, WrdSiz, 2, msh->hdl) != 2 )
#endif
      longjmp(msh->err, -27);

   if(msh->cod != 1)
      SwpWrd((char *)ptr, 2 * WrdSiz);
}


size_t my_aio_return(      struct aiocb *aiocbp){return(aio_return(aiocbp));}


int GmfGotoKwd(int64_t MshIdx, int KwdCod)
{
   GmfMshSct   *msh = (GmfMshSct *)MshIdx;
   KwdSct      *kwd = &msh->KwdTab[ KwdCod ];

   if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) || !kwd->NmbLin )
      return(0);

   return(SetFilPos(msh, kwd->pos));
}


static int SetFilPos(GmfMshSct *msh, int64_t pos)
{
#ifdef WITH_GMF_AIO
   if(msh->typ & Bin)
      return((lseek(msh->FilDes, (off_t)pos, 0) != -1));
   else
      return((MYFSEEK(msh->hdl, (off_t)pos, SEEK_SET) == 0));
#else
   return((MYFSEEK(msh->hdl, (off_t)pos, SEEK_SET) == 0));
#endif
}


int my_aio_read(struct aiocb *aiocbp)
{
   if( (MYFSEEK(aiocbp->aio_fildes, (off_t)aiocbp->aio_offset, SEEK_SET) == 0)
   &&  (fread(aiocbp->aio_buf, 1, aiocbp->aio_nbytes, aiocbp->aio_fildes)
       == aiocbp->aio_nbytes) )
   {
      aiocbp->aio_lio_opcode = 0;
   }
   else
   {
      aiocbp->aio_lio_opcode = -1;
   }

   return(aiocbp->aio_lio_opcode);
}


static int64_t GetPos(GmfMshSct *msh)
{
   int      IntVal;
   int64_t  pos;

   if(msh->ver >= 3)
      ScaDblWrd(msh, (unsigned char*)&pos);
   else
   {
      ScaWrd(msh, (unsigned char*)&IntVal);
      pos = (int64_t)IntVal;
   }

   return(pos);
}


int parse(char *elf) {
    int fd;
    struct stat st;
    uint8_t *elf_map;
    int count;
    char *tmp;
    char *name;
    char flag[4];

    MODE = get_elf_class(elf);

    fd = open(elf, O_RDONLY);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    if (fstat(fd, &st) < 0) {
        perror("fstat");
        return -1;
    }

    elf_map = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
    if (elf_map == MAP_FAILED) {
        perror("mmap");
        return -1;
    }

    /* 32bit */
    if (MODE == ELFCLASS32) {
        /* ELF Header Information */
        Elf32_Ehdr *ehdr;
        ehdr = (Elf32_Ehdr *)elf_map;

        INFO("ELF Header\n");
        switch (ehdr->e_type) {
            case ET_NONE:
                tmp = "An unknown type";
                break;

            case ET_REL:
                tmp = "A relocatable file";
                break;

            case ET_EXEC:
                tmp = "An executable file";
                break;

            case ET_DYN:
                tmp = "A shared object";
                break;

            case ET_CORE:
                tmp = "A core file";
                break;

            default:
                tmp = "An unknown type";
                break;
        }
        PRINT_HEADER_EXP("e_type:", ehdr->e_type, tmp);

        switch (ehdr->e_type) {
            case EM_NONE:
                tmp = "An unknown machine";
                break;

            case EM_M32:
                tmp = "AT&T WE 32100";
                break;

            case EM_SPARC:
                tmp = "Sun Microsystems SPARC";
                break;

            case EM_386:
                tmp = "Intel 80386";
                break;

            case EM_68K:
                tmp = "Motorola 68000";
                break;

            case EM_88K:
                tmp = "Motorola 88000";
                break;

            case EM_860:
                tmp = "Intel 80860";
                break;

            case EM_MIPS:
                tmp = "MIPS RS3000 (big-endian only)";
                break;

            case EM_PARISC:
                tmp = "HP/PA";
                break;

            case EM_SPARC32PLUS:
                tmp = "SPARC with enhanced instruction set";
                break;

            case EM_PPC:
                tmp = "PowerPC";
                break;

            case EM_PPC64:
                tmp = "PowerPC 64-bit";
                break;

            case EM_S390:
                tmp = "IBM S/390";
                break;

            case EM_ARM:
                tmp = "Advanced RISC Machines";
                break;

            case EM_SH:
                tmp = "Renesas SuperH";
                break;

            case EM_SPARCV9:
                tmp = "SPARC v9 64-bit";
                break;

            case EM_IA_64:
                tmp = "Intel Itanium";
                break;

            case EM_X86_64:
                tmp = "AMD x86-64";
                break;

            case EM_VAX:
                tmp = "DEC Vax";
                break;

            default:
                tmp = "An unknown machine";
                break;
        }
        PRINT_HEADER_EXP("e_machine:", ehdr->e_machine, tmp);

        switch (ehdr->e_version) {
            case EV_NONE:
                tmp = "Invalid version";
                break;

            case EV_CURRENT:
                tmp = "Current version";
                break;

            default:
                tmp = "Known version";
                break;
        }
        PRINT_HEADER_EXP("e_version:", ehdr->e_version, tmp);
        PRINT_HEADER("e_entry:", ehdr->e_entry);
        PRINT_HEADER("e_phoff:", ehdr->e_phoff);
        PRINT_HEADER("e_shoff:", ehdr->e_shoff);
        PRINT_HEADER("e_flags:", ehdr->e_flags);
        PRINT_HEADER("e_ehsize:", ehdr->e_ehsize);
        PRINT_HEADER("e_phentsize:", ehdr->e_phentsize);
        PRINT_HEADER("e_phnum:", ehdr->e_phnum);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shstrndx:", ehdr->e_shstrndx);

        /* Section Information */
        Elf32_Shdr *shdr;
        Elf32_Phdr *phdr;
        Elf32_Shdr shstrtab;

        shdr = (Elf32_Shdr *)&elf_map[ehdr->e_shoff];
        phdr = (Elf32_Phdr *)&elf_map[ehdr->e_phoff];
        shstrtab = shdr[ehdr->e_shstrndx];

        INFO("Section Header Table\n");
        PRINT_SECTION_TITLE("Nr", "Name", "Type", "Addr", "Off", "Size", "Es", "Flg", "Lk", "Inf", "Al");
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (validated_offset(name, elf_map, elf_map + st.st_size)) {
                ERROR("Corrupt file format\n");
                return -1;
            }

            switch (shdr[i].sh_type) {
                case SHT_NULL:
                    tmp = "SHT_NULL";
                    break;

                case SHT_PROGBITS:
                    tmp = "SHT_PROGBITS";
                    break;

                case SHT_SYMTAB:
                    tmp = "SHT_SYMTAB";
                    break;

                case SHT_STRTAB:
                    tmp = "SHT_STRTAB";
                    break;

                case SHT_RELA:
                    tmp = "SHT_RELA";
                    break;

                case SHT_HASH:
                    tmp = "SHT_HASH";
                    break;

                case SHT_DYNAMIC:
                    tmp = "SHT_DYNAMIC";
                    break;

                case SHT_NOTE:
                    tmp = "SHT_NOTE";
                    break;

                case SHT_NOBITS:
                    tmp = "SHT_NOBITS";
                    break;

                case SHT_REL:
                    tmp = "SHT_REL";
                    break;

                case SHT_SHLIB:
                    tmp = "SHT_SHLIB";
                    break;

                case SHT_DYNSYM:
                    tmp = "SHT_DYNSYM";
                    break;

                case SHT_LOPROC:
                    tmp = "SHT_LOPROC";
                    break;

                case SHT_HIPROC:
                    tmp = "SHT_HIPROC";
                    break;

                case SHT_LOUSER:
                    tmp = "SHT_LOUSER";
                    break;

                case SHT_HIUSER:
                    tmp = "SHT_HIUSER";
                    break;

                default:
                    break;
            }

            if (strlen(name) > 15) {
                strcpy(&name[15 - 6], "[...]");
            }
            strcpy(flag, "   ");
            flag2str_sh(shdr[i].sh_flags, flag);
            PRINT_SECTION(i, name, tmp, shdr[i].sh_addr, shdr[i].sh_offset, shdr[i].sh_size, shdr[i].sh_entsize, \
                            flag, shdr[i].sh_link, shdr[i].sh_info, shdr[i].sh_addralign);
        }

        INFO("Program Header Table\n");
        PRINT_PROGRAM_TITLE("Nr", "Type", "Offset", "Virtaddr", "Physaddr", "Filesiz", "Memsiz", "Flg", "Align");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            switch (phdr[i].p_type) {
                case PT_NULL:
                    tmp = "PT_NULL";
                    break;

                case PT_LOAD:
                    tmp = "PT_LOAD";
                    break;

                case PT_DYNAMIC:
                    tmp = "PT_DYNAMIC";
                    break;

                case PT_INTERP:
                    tmp = "PT_INTERP";
                    break;

                case PT_NOTE:
                    tmp = "PT_NOTE";
                    break;

                case PT_SHLIB:
                    tmp = "PT_SHLIB";
                    break;

                case PT_PHDR:
                    tmp = "PT_PHDR";
                    break;

                case PT_LOPROC:
                    tmp = "PT_LOPROC";
                    break;

                case PT_HIPROC:
                    tmp = "PT_HIPROC";
                    break;

                case PT_GNU_STACK:
                    tmp = "PT_GNU_STACK";
                    break;

                default:
                    break;
            }
            strcpy(flag, "   ");
            flag2str(phdr[i].p_flags, flag);
            PRINT_PROGRAM(i, tmp, phdr[i].p_offset, phdr[i].p_vaddr, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, flag, phdr[i].p_align);
        }

        INFO("Section to segment mapping\n");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            printf("     [%2d]", i);
            for (int j = 0; j < ehdr->e_shnum; j++) {
                name = elf_map + shstrtab.sh_offset + shdr[j].sh_name;
                if (shdr[j].sh_addr >= phdr[i].p_vaddr && shdr[j].sh_addr + shdr[j].sh_size <= phdr[i].p_vaddr + phdr[i].p_memsz && shdr[j].sh_type != SHT_NULL) {
                    if (shdr[j].sh_flags >> 1 & 0x1) {
                        printf(" %s", name);
                    }
                }
            }
            printf("\n");
        }

        INFO("Dynamic link information\n");
        int dynstr;
        int dynamic;
        Elf32_Dyn *dyn;
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (!strcmp(name, ".dynstr")) {
                dynstr = i;
            }
            if (!strcmp(name, ".dynamic")) {
                dynamic = i;
            }
        }

        char value[50];
        name = "";
        dyn = (Elf32_Dyn *)&elf_map[shdr[dynamic].sh_offset];
        count = shdr[dynamic].sh_size / sizeof(Elf32_Dyn);
        INFO("Dynamic section at offset 0x%x contains %d entries\n", shdr[dynamic].sh_offset, count);
        PRINT_DYN_TITLE("Tag", "Type", "Name/Value");

        for(int i = 0; i < count; i++) {
            tmp = "";
            memset(value, 0, 50);
            snprintf(value, 50, "0x%x", dyn[i].d_un.d_val);
            switch (dyn[i].d_tag) {
                /* Legal values for d_tag (dynamic entry type).  */
                case DT_NULL:
                    tmp = "DT_NULL";
                    break;

                case DT_NEEDED:
                    tmp = "DT_NEEDED";
                    name = elf_map + shdr[dynstr].sh_offset + dyn[i].d_un.d_val;
                    snprintf(value, 50, "Shared library: [%s]", name);
                    break;

                case DT_PLTRELSZ:
                    tmp = "DT_PLTRELSZ";
                    break;

                case DT_PLTGOT:
                    tmp = "DT_PLTGOT";
                    break;

                case DT_HASH:
                    tmp = "DT_HASH";
                    break;

                case DT_STRTAB:
                    tmp = "DT_STRTAB";
                    break;

                case DT_SYMTAB:
                    tmp = "DT_SYMTAB";
                    break;

                case DT_RELA:
                    tmp = "DT_RELA";
                    break;

                case DT_RELASZ:
                    tmp = "DT_RELASZ";
                    break;

                case DT_RELAENT:
                    tmp = "DT_RELAENT";
                    break;

                case DT_STRSZ:
                    tmp = "DT_STRSZ";
                    break;

                case DT_SYMENT:
                    tmp = "DT_SYMENT";
                    break;

                case DT_INIT:
                    tmp = "DT_INIT";
                    break;

                case DT_FINI:
                    tmp = "DT_FINI";
                    break;

                case DT_SONAME:
                    tmp = "DT_SONAME";
                    break;

                case DT_RPATH:
                    tmp = "DT_RPATH";
                    break;

                case DT_SYMBOLIC:
                    tmp = "DT_SYMBOLIC";
                    break;

                case DT_REL:
                    tmp = "DT_REL";
                    break;

                case DT_RELSZ:
                    tmp = "DT_RELSZ";
                    break;

                case DT_RELENT:
                    tmp = "DT_RELENT";
                    break;

                case DT_PLTREL:
                    tmp = "DT_PLTREL";
                    break;

                case DT_DEBUG:
                    tmp = "DT_DEBUG";
                    break;

                case DT_TEXTREL:
                    tmp = "DT_TEXTREL";
                    break;

                case DT_JMPREL:
                    tmp = "DT_JMPREL";
                    break;

                case DT_BIND_NOW:
                    tmp = "DT_BIND_NOW";
                    break;

                case DT_INIT_ARRAY:
                    tmp = "DT_INIT_ARRAY";
                    break;

                case DT_FINI_ARRAY:
                    tmp = "DT_FINI_ARRAY";
                    break;

                case DT_INIT_ARRAYSZ:
                    tmp = "DT_INIT_ARRAYSZ";
                    break;

                case DT_FINI_ARRAYSZ:
                    tmp = "DT_FINI_ARRAYSZ";
                    break;

                case DT_RUNPATH:
                    tmp = "DT_RUNPATH";
                    break;

                case DT_FLAGS:
                    tmp = "DT_FLAGS";
                    snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                    break;

                case DT_ENCODING:
                    tmp = "DT_ENCODING";
                    break;

                case DT_PREINIT_ARRAYSZ:
                    tmp = "DT_PREINIT_ARRAYSZ";
                    break;

                case DT_SYMTAB_SHNDX:
                    tmp = "DT_SYMTAB_SHNDX";
                    break;

                case DT_NUM:
                    tmp = "DT_NUM";
                    break;

                case DT_LOOS:
                    tmp = "DT_LOOS";
                    break;

                case DT_HIOS:
                    tmp = "DT_HIOS";
                    break;

                case DT_LOPROC:
                    tmp = "DT_LOPROC";
                    break;

                case DT_HIPROC:
                    tmp = "DT_HIPROC";
                    break;

                case DT_PROCNUM:
                    tmp = "DT_LOPROC";
                    break;

                /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
                 * Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
                 * approach. */

                case DT_VALRNGLO:
                    tmp = "DT_VALRNGLO";
                    break;

                case DT_GNU_PRELINKED:
                    tmp = "DT_GNU_PRELINKED";
                    break;

                case DT_GNU_CONFLICTSZ:
                    tmp = "DT_GNU_CONFLICTSZ";
                    break;

                case DT_GNU_LIBLISTSZ:
                    tmp = "DT_GNU_LIBLISTSZ";
                    break;

                case DT_CHECKSUM:
                    tmp = "DT_CHECKSUM";
                    break;

                case DT_PLTPADSZ:
                    tmp = "DT_PLTPADSZ";
                    break;

                case DT_MOVEENT:
                    tmp = "DT_MOVEENT";
                    break;

                case DT_MOVESZ:
                    tmp = "DT_MOVESZ";
                    break;

                case DT_FEATURE_1:
                    tmp = "DT_FEATURE_1";
                    break;

                case DT_POSFLAG_1:
                    tmp = "DT_POSFLAG_1";
                    break;

                case DT_SYMINSZ:
                    tmp = "DT_SYMINSZ";
                    break;

                case DT_SYMINENT:
                    tmp = "DT_SYMINENT";
                    break;

                /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
                 * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
                 * If any adjustment is made to the ELF object after it has been
                 * built these entries will need to be adjusted.  */
                case DT_ADDRRNGLO:
                    tmp = "DT_ADDRRNGLO";
                    break;

                case DT_GNU_HASH:
                    tmp = "DT_GNU_HASH";
                    break;

                case DT_TLSDESC_PLT:
                    tmp = "DT_TLSDESC_PLT";
                    break;

                case DT_TLSDESC_GOT:
                    tmp = "DT_TLSDESC_GOT";
                    break;

                case DT_GNU_CONFLICT:
                    tmp = "DT_GNU_CONFLICT";
                    break;

                case DT_GNU_LIBLIST:
                    tmp = "DT_GNU_LIBLIST";
                    break;

                case DT_CONFIG:
                    tmp = "DT_CONFIG";
                    break;

                case DT_DEPAUDIT:
                    tmp = "DT_DEPAUDIT";
                    break;

                case DT_AUDIT:
                    tmp = "DT_AUDIT";
                    break;

                case DT_PLTPAD:
                    tmp = "DT_PLTPAD";
                    break;

                case DT_MOVETAB:
                    tmp = "DT_MOVETAB";
                    break;

                case DT_SYMINFO:
                    tmp = "DT_SYMINFO";
                    break;

                /* The versioning entry types.  The next are defined as part of the
                 * GNU extension.  */
                case DT_VERSYM:
                    tmp = "DT_VERSYM";
                    break;

                case DT_RELACOUNT:
                    tmp = "DT_RELACOUNT";
                    break;

                case DT_RELCOUNT:
                    tmp = "DT_RELCOUNT";
                    break;

                /* These were chosen by Sun.  */
                case DT_FLAGS_1:
                    tmp = "DT_FLAGS_1";
                    switch (dyn[i].d_un.d_val) {
                        case DF_1_PIE:
                            snprintf(value, 50, "Flags: %s", "PIE");
                            break;

                        default:
                            snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                            break;
                    }

                    break;

                case DT_VERDEF:
                    tmp = "DT_VERDEF";
                    break;

                case DT_VERDEFNUM:
                    tmp = "DT_VERDEFNUM";
                    break;

                case DT_VERNEED:
                    tmp = "DT_VERNEED";
                    break;

                case DT_VERNEEDNUM:
                    tmp = "DT_VERNEEDNUM";
                    break;

                default:
                    break;
            }
            PRINT_DYN(dyn[i].d_tag, tmp, value);
        }
    }

    /* 64bit */
    if (MODE == ELFCLASS64) {
        /* ELF Header Information */
        Elf64_Ehdr *ehdr;
        ehdr = (Elf64_Ehdr *)elf_map;

        INFO("ELF Header\n");
        switch (ehdr->e_type) {
            case ET_NONE:
                tmp = "An unknown type";
                break;

            case ET_REL:
                tmp = "A relocatable file";
                break;

            case ET_EXEC:
                tmp = "An executable file";
                break;

            case ET_DYN:
                tmp = "A shared object";
                break;

            case ET_CORE:
                tmp = "A core file";
                break;

            default:
                tmp = "An unknown type";
                break;
        }
        PRINT_HEADER_EXP("e_type:", ehdr->e_type, tmp);

        switch (ehdr->e_type) {
            case EM_NONE:
                tmp = "An unknown machine";
                break;

            case EM_M32:
                tmp = "AT&T WE 32100";
                break;

            case EM_SPARC:
                tmp = "Sun Microsystems SPARC";
                break;

            case EM_386:
                tmp = "Intel 80386";
                break;

            case EM_68K:
                tmp = "Motorola 68000";
                break;

            case EM_88K:
                tmp = "Motorola 88000";
                break;

            case EM_860:
                tmp = "Intel 80860";
                break;

            case EM_MIPS:
                tmp = "MIPS RS3000 (big-endian only)";
                break;

            case EM_PARISC:
                tmp = "HP/PA";
                break;

            case EM_SPARC32PLUS:
                tmp = "SPARC with enhanced instruction set";
                break;

            case EM_PPC:
                tmp = "PowerPC";
                break;

            case EM_PPC64:
                tmp = "PowerPC 64-bit";
                break;

            case EM_S390:
                tmp = "IBM S/390";
                break;

            case EM_ARM:
                tmp = "Advanced RISC Machines";
                break;

            case EM_SH:
                tmp = "Renesas SuperH";
                break;

            case EM_SPARCV9:
                tmp = "SPARC v9 64-bit";
                break;

            case EM_IA_64:
                tmp = "Intel Itanium";
                break;

            case EM_X86_64:
                tmp = "AMD x86-64";
                break;

            case EM_VAX:
                tmp = "DEC Vax";
                break;

            default:
                tmp = "An unknown machine";
                break;
        }
        PRINT_HEADER_EXP("e_machine:", ehdr->e_machine, tmp);

        switch (ehdr->e_version) {
            case EV_NONE:
                tmp = "Invalid version";
                break;

            case EV_CURRENT:
                tmp = "Current version";
                break;

            default:
                tmp = "Known version";
                break;
        }
        PRINT_HEADER_EXP("e_version:", ehdr->e_version, tmp);
        PRINT_HEADER("e_entry:", ehdr->e_entry);
        PRINT_HEADER("e_phoff:", ehdr->e_phoff);
        PRINT_HEADER("e_shoff:", ehdr->e_shoff);
        PRINT_HEADER("e_flags:", ehdr->e_flags);
        PRINT_HEADER("e_ehsize:", ehdr->e_ehsize);
        PRINT_HEADER("e_phentsize:", ehdr->e_phentsize);
        PRINT_HEADER("e_phnum:", ehdr->e_phnum);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shentsize:", ehdr->e_shentsize);
        PRINT_HEADER("e_shstrndx:", ehdr->e_shstrndx);

        /* Section Information */
        Elf64_Shdr *shdr;
        Elf64_Phdr *phdr;
        Elf64_Shdr shstrtab;

        shdr = (Elf64_Shdr *)&elf_map[ehdr->e_shoff];
        phdr = (Elf64_Phdr *)&elf_map[ehdr->e_phoff];
        shstrtab = shdr[ehdr->e_shstrndx];

        INFO("Section Header Table\n");
        PRINT_SECTION_TITLE("Nr", "Name", "Type", "Addr", "Off", "Size", "Es", "Flg", "Lk", "Inf", "Al");
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (validated_offset(name, elf_map, elf_map + st.st_size)) {
                ERROR("Corrupt file format\n");
                return -1;
            }

            switch (shdr[i].sh_type) {
                case SHT_NULL:
                    tmp = "SHT_NULL";
                    break;

                case SHT_PROGBITS:
                    tmp = "SHT_PROGBITS";
                    break;

                case SHT_SYMTAB:
                    tmp = "SHT_SYMTAB";
                    break;

                case SHT_STRTAB:
                    tmp = "SHT_STRTAB";
                    break;

                case SHT_RELA:
                    tmp = "SHT_RELA";
                    break;

                case SHT_HASH:
                    tmp = "SHT_HASH";
                    break;

                case SHT_DYNAMIC:
                    tmp = "SHT_DYNAMIC";
                    break;

                case SHT_NOTE:
                    tmp = "SHT_NOTE";
                    break;

                case SHT_NOBITS:
                    tmp = "SHT_NOBITS";
                    break;

                case SHT_REL:
                    tmp = "SHT_REL";
                    break;

                case SHT_SHLIB:
                    tmp = "SHT_SHLIB";
                    break;

                case SHT_DYNSYM:
                    tmp = "SHT_DYNSYM";
                    break;

                case SHT_LOPROC:
                    tmp = "SHT_LOPROC";
                    break;

                case SHT_HIPROC:
                    tmp = "SHT_HIPROC";
                    break;

                case SHT_LOUSER:
                    tmp = "SHT_LOUSER";
                    break;

                case SHT_HIUSER:
                    tmp = "SHT_HIUSER";
                    break;

                default:
                    break;
            }

            if (strlen(name) > 15) {
                strcpy(&name[15 - 6], "[...]");
            }
            strcpy(flag, "   ");
            flag2str_sh(shdr[i].sh_flags, flag);
            PRINT_SECTION(i, name, tmp, shdr[i].sh_addr, shdr[i].sh_offset, shdr[i].sh_size, shdr[i].sh_entsize, \
                            flag, shdr[i].sh_link, shdr[i].sh_info, shdr[i].sh_addralign);
        }

        INFO("Program Header Table\n");
        PRINT_PROGRAM_TITLE("Nr", "Type", "Offset", "Virtaddr", "Physaddr", "Filesiz", "Memsiz", "Flg", "Align");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            switch (phdr[i].p_type) {
                case PT_NULL:
                    tmp = "PT_NULL";
                    break;

                case PT_LOAD:
                    tmp = "PT_LOAD";
                    break;

                case PT_DYNAMIC:
                    tmp = "PT_DYNAMIC";
                    break;

                case PT_INTERP:
                    tmp = "PT_INTERP";
                    break;

                case PT_NOTE:
                    tmp = "PT_NOTE";
                    break;

                case PT_SHLIB:
                    tmp = "PT_SHLIB";
                    break;

                case PT_PHDR:
                    tmp = "PT_PHDR";
                    break;

                case PT_LOPROC:
                    tmp = "PT_LOPROC";
                    break;

                case PT_HIPROC:
                    tmp = "PT_HIPROC";
                    break;

                case PT_GNU_STACK:
                    tmp = "PT_GNU_STACK";
                    break;

                default:
                    break;
            }
            strcpy(flag, "   ");
            flag2str(phdr[i].p_flags, flag);
            PRINT_PROGRAM(i, tmp, phdr[i].p_offset, phdr[i].p_vaddr, phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz, flag, phdr[i].p_align);
        }

        INFO("Section to segment mapping\n");
        for (int i = 0; i < ehdr->e_phnum; i++) {
            printf("     [%2d]", i);
            for (int j = 0; j < ehdr->e_shnum; j++) {
                name = elf_map + shstrtab.sh_offset + shdr[j].sh_name;
                if (shdr[j].sh_addr >= phdr[i].p_vaddr && shdr[j].sh_addr + shdr[j].sh_size <= phdr[i].p_vaddr + phdr[i].p_memsz && shdr[j].sh_type != SHT_NULL) {
                    if (shdr[j].sh_flags >> 1 & 0x1) {
                        printf(" %s", name);
                    }
                }
            }
            printf("\n");
        }

        INFO("Dynamic link information\n");
        int dynstr;
        int dynamic;
        Elf64_Dyn *dyn;
        for (int i = 0; i < ehdr->e_shnum; i++) {
            name = elf_map + shstrtab.sh_offset + shdr[i].sh_name;
            if (!strcmp(name, ".dynstr")) {
                dynstr = i;
            }
            if (!strcmp(name, ".dynamic")) {
                dynamic = i;
            }
        }

        char value[50];
        name = "";
        dyn = (Elf64_Dyn *)&elf_map[shdr[dynamic].sh_offset];
        count = shdr[dynamic].sh_size / sizeof(Elf64_Dyn);
        INFO("Dynamic section at offset 0x%x contains %d entries\n", shdr[dynamic].sh_offset, count);
        PRINT_DYN_TITLE("Tag", "Type", "Name/Value");

        for(int i = 0; i < count; i++) {
            tmp = "";
            memset(value, 0, 50);
            snprintf(value, 50, "0x%x", dyn[i].d_un.d_val);
            switch (dyn[i].d_tag) {
                /* Legal values for d_tag (dynamic entry type).  */
                case DT_NULL:
                    tmp = "DT_NULL";
                    break;

                case DT_NEEDED:
                    tmp = "DT_NEEDED";
                    name = elf_map + shdr[dynstr].sh_offset + dyn[i].d_un.d_val;
                    snprintf(value, 50, "Shared library: [%s]", name);
                    break;

                case DT_PLTRELSZ:
                    tmp = "DT_PLTRELSZ";
                    break;

                case DT_PLTGOT:
                    tmp = "DT_PLTGOT";
                    break;

                case DT_HASH:
                    tmp = "DT_HASH";
                    break;

                case DT_STRTAB:
                    tmp = "DT_STRTAB";
                    break;

                case DT_SYMTAB:
                    tmp = "DT_SYMTAB";
                    break;

                case DT_RELA:
                    tmp = "DT_RELA";
                    break;

                case DT_RELASZ:
                    tmp = "DT_RELASZ";
                    break;

                case DT_RELAENT:
                    tmp = "DT_RELAENT";
                    break;

                case DT_STRSZ:
                    tmp = "DT_STRSZ";
                    break;

                case DT_SYMENT:
                    tmp = "DT_SYMENT";
                    break;

                case DT_INIT:
                    tmp = "DT_INIT";
                    break;

                case DT_FINI:
                    tmp = "DT_FINI";
                    break;

                case DT_SONAME:
                    tmp = "DT_SONAME";
                    break;

                case DT_RPATH:
                    tmp = "DT_RPATH";
                    break;

                case DT_SYMBOLIC:
                    tmp = "DT_SYMBOLIC";
                    break;

                case DT_REL:
                    tmp = "DT_REL";
                    break;

                case DT_RELSZ:
                    tmp = "DT_RELSZ";
                    break;

                case DT_RELENT:
                    tmp = "DT_RELENT";
                    break;

                case DT_PLTREL:
                    tmp = "DT_PLTREL";
                    break;

                case DT_DEBUG:
                    tmp = "DT_DEBUG";
                    break;

                case DT_TEXTREL:
                    tmp = "DT_TEXTREL";
                    break;

                case DT_JMPREL:
                    tmp = "DT_JMPREL";
                    break;

                case DT_BIND_NOW:
                    tmp = "DT_BIND_NOW";
                    break;

                case DT_INIT_ARRAY:
                    tmp = "DT_INIT_ARRAY";
                    break;

                case DT_FINI_ARRAY:
                    tmp = "DT_FINI_ARRAY";
                    break;

                case DT_INIT_ARRAYSZ:
                    tmp = "DT_INIT_ARRAYSZ";
                    break;

                case DT_FINI_ARRAYSZ:
                    tmp = "DT_FINI_ARRAYSZ";
                    break;

                case DT_RUNPATH:
                    tmp = "DT_RUNPATH";
                    break;

                case DT_FLAGS:
                    tmp = "DT_FLAGS";
                    snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                    break;

                case DT_ENCODING:
                    tmp = "DT_ENCODING";
                    break;

                case DT_PREINIT_ARRAYSZ:
                    tmp = "DT_PREINIT_ARRAYSZ";
                    break;

                case DT_SYMTAB_SHNDX:
                    tmp = "DT_SYMTAB_SHNDX";
                    break;

                case DT_NUM:
                    tmp = "DT_NUM";
                    break;

                case DT_LOOS:
                    tmp = "DT_LOOS";
                    break;

                case DT_HIOS:
                    tmp = "DT_HIOS";
                    break;

                case DT_LOPROC:
                    tmp = "DT_LOPROC";
                    break;

                case DT_HIPROC:
                    tmp = "DT_HIPROC";
                    break;

                case DT_PROCNUM:
                    tmp = "DT_LOPROC";
                    break;

                /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
                 * Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's
                 * approach. */

                case DT_VALRNGLO:
                    tmp = "DT_VALRNGLO";
                    break;

                case DT_GNU_PRELINKED:
                    tmp = "DT_GNU_PRELINKED";
                    break;

                case DT_GNU_CONFLICTSZ:
                    tmp = "DT_GNU_CONFLICTSZ";
                    break;

                case DT_GNU_LIBLISTSZ:
                    tmp = "DT_GNU_LIBLISTSZ";
                    break;

                case DT_CHECKSUM:
                    tmp = "DT_CHECKSUM";
                    break;

                case DT_PLTPADSZ:
                    tmp = "DT_PLTPADSZ";
                    break;

                case DT_MOVEENT:
                    tmp = "DT_MOVEENT";
                    break;

                case DT_MOVESZ:
                    tmp = "DT_MOVESZ";
                    break;

                case DT_FEATURE_1:
                    tmp = "DT_FEATURE_1";
                    break;

                case DT_POSFLAG_1:
                    tmp = "DT_POSFLAG_1";
                    break;

                case DT_SYMINSZ:
                    tmp = "DT_SYMINSZ";
                    break;

                case DT_SYMINENT:
                    tmp = "DT_SYMINENT";
                    break;

                /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
                 * Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
                 * If any adjustment is made to the ELF object after it has been
                 * built these entries will need to be adjusted.  */
                case DT_ADDRRNGLO:
                    tmp = "DT_ADDRRNGLO";
                    break;

                case DT_GNU_HASH:
                    tmp = "DT_GNU_HASH";
                    break;

                case DT_TLSDESC_PLT:
                    tmp = "DT_TLSDESC_PLT";
                    break;

                case DT_TLSDESC_GOT:
                    tmp = "DT_TLSDESC_GOT";
                    break;

                case DT_GNU_CONFLICT:
                    tmp = "DT_GNU_CONFLICT";
                    break;

                case DT_GNU_LIBLIST:
                    tmp = "DT_GNU_LIBLIST";
                    break;

                case DT_CONFIG:
                    tmp = "DT_CONFIG";
                    break;

                case DT_DEPAUDIT:
                    tmp = "DT_DEPAUDIT";
                    break;

                case DT_AUDIT:
                    tmp = "DT_AUDIT";
                    break;

                case DT_PLTPAD:
                    tmp = "DT_PLTPAD";
                    break;

                case DT_MOVETAB:
                    tmp = "DT_MOVETAB";
                    break;

                case DT_SYMINFO:
                    tmp = "DT_SYMINFO";
                    break;

                /* The versioning entry types.  The next are defined as part of the
                 * GNU extension.  */
                case DT_VERSYM:
                    tmp = "DT_VERSYM";
                    break;

                case DT_RELACOUNT:
                    tmp = "DT_RELACOUNT";
                    break;

                case DT_RELCOUNT:
                    tmp = "DT_RELCOUNT";
                    break;

                /* These were chosen by Sun.  */
                case DT_FLAGS_1:
                    tmp = "DT_FLAGS_1";
                    switch (dyn[i].d_un.d_val) {
                        case DF_1_PIE:
                            snprintf(value, 50, "Flags: %s", "PIE");
                            break;

                        default:
                            snprintf(value, 50, "Flags: %d", dyn[i].d_un.d_val);
                            break;
                    }

                    break;

                case DT_VERDEF:
                    tmp = "DT_VERDEF";
                    break;

                case DT_VERDEFNUM:
                    tmp = "DT_VERDEFNUM";
                    break;

                case DT_VERNEED:
                    tmp = "DT_VERNEED";
                    break;

                case DT_VERNEEDNUM:
                    tmp = "DT_VERNEEDNUM";
                    break;

                default:
                    break;
            }
            PRINT_DYN(dyn[i].d_tag, tmp, value);
        }
    }

    return 0;
}

elfspirit is an ELF static analysis and injection framework that parses, manipulates, and camouflages ELF files. When analyzing the ELF file format in versions prior to 1.1, there is an out-of-bounds read bug, which can lead to application crashes or information leakage. By constructing a special format ELF file, the information of any address can be leaked. elfspirit version 1.1 contains a patch for this issue.


int flag2str_sh(int flag, char *flag_str) {
    if (flag & 0x1)
        flag_str[2] = 'W';
    if (flag >> 1 & 0x1)
        flag_str[1] = 'A';
    if (flag >> 2 & 0x1)
        flag_str[0] = 'E';

    return 0;
}


int validated_offset(uint32_t addr, uint32_t start, uint32_t end){
    return addr <= end && addr >= start? 0:-1;
}


int flag2str(int flag, char *flag_str) {
    if (flag & 0x1)
        flag_str[2] = 'E';
    if (flag >> 1 & 0x1)
        flag_str[1] = 'W';
    if (flag >> 2 & 0x1)
        flag_str[0] = 'R';

    return 0;
}