Operating System - OpenVMS
1753594 Members
6351 Online
108796 Solutions
New Discussion юеВ

Re: ANALYZE/IMAGE callable interface?

 
SOLVED
Go to solution
Kay Dolle
Advisor

ANALYZE/IMAGE callable interface?

Hi, we are used to link our images with an ID over the optionfile. On DCL we can determine that with ANALYZE/IMAGE/SELECT=IDENTIFICATION=IMAGE, but is there an LIB$ or an SYS$ to retrieve that information in a program?
Background: we are porting from ALPHA to I64 and out old function reads the image file at an fixed position. The position has changed on I64 and we would like to do it better now...
24 REPLIES 24
Wim Van den Wyngaert
Honored Contributor
Solution

Re: ANALYZE/IMAGE callable interface?

Kay Dolle
Advisor

Re: ANALYZE/IMAGE callable interface?

Great, Wim!
Thank you Steve Hoffman!
Kay
Hein van den Heuvel
Honored Contributor

Re: ANALYZE/IMAGE callable interface?

Kay,

Is that really working for you?
Seems like Alpha code to me.
You need some ELF functions like elf_getindent.

If you link Hoff's example with /sysexe then the critical function IMG$DECODE_IHD is resolved but does work as coded.


Is this for the purpose of obtaining the image ident for the current image?

For ALPHA ... and if you are willing to link /sysexe without actually calling system stuff, or willing to hardcode a defintion of MMG$IMGHDRBUF to be 7FFCF800 you can use the code I wrote below. I wrote the example for intended cobol usage in a shareable library. Sample below.

Regards,
Hein van den Heuvel

$
$ type GET_IDENT.C
/*
** Compile with: sys$library:sys$lib_c.tlb/lib
** Link with /sysexe
*/
#include
#include
#include
#include

#define MOVE_FIELD(f) \
p = &eihi->eihi$t_ ## f ## [0]; \
l = *p++; \
ident-> ## f ## _length = l; \
p = memcpy ( &ident-> ## f ## , p, l ); \
e = p + sizeof ident-> ## f ; \
p += l; \
while (p < e) *p++ = ' ';\
*p = 0;

struct image_identification {
unsigned int imgnam_length;
unsigned int imgid_length;
unsigned int linkid_length;
unsigned int imgbid_length;

unsigned __int64 linktime; /*DATE TIME THIS IMAGE WAS LINKED */
char imgnam[40]; /*IMAGE NAME STRING */
char imgid[16]; /*IMAGE IDENT STRING */
char linkid[16]; /*LINKER IDENT STRING */
char imgbid[16]; /*IMAGE BUILD IDENT STRING */
char linktime_text[24];
};

unsigned int sys$asctim();

globalref EIHD *MMG$IMGHDRBUF;

unsigned int get_image_name_and_ident (struct image_identification *ident)
{
struct {int len; char *addr;} time_desc;
EIHD *eihd;
EIHI *eihi;
unsigned int l, s;
char *p, *e;
eihd = MMG$IMGHDRBUF;
eihi = (EIHI *)((char *) eihd + eihd->eihd$l_imgidoff);


ident->linktime = eihi->eihi$q_linktime;

time_desc.len = sizeof ident->linktime_text;
time_desc.addr = ident->linktime_text;

s = sys$asctim(0, &time_desc, &eihi->eihi$q_linktime);

MOVE_FIELD(imgnam);
MOVE_FIELD(imgid);
MOVE_FIELD(linkid);
MOVE_FIELD(imgbid);
return s;
}

$
$ type IMAGE-IDENT-CALLING.COB
IDENTIFICATION DIVISION.
PROGRAM-ID. prn-test IDENT "test:1234".
DATA DIVISION.
WORKING-STORAGE SECTION.

01 image_identification.
03 imgnam_length pic s9(9) comp.
03 imgid_length pic s9(9) comp.
03 linkid_length pic s9(9) comp.
03 imgbid_length pic s9(9) comp.
03 link-time pic s9(11)v9(7) comp.
03 image-name pic x(39).
03 filler pic x.
03 image-ident pic x(15).
03 filler pic x.
03 linker-ident pic x(15).
03 filler pic x.
03 build-ident pic x(15).
03 filler pic x.
03 link-time-text pic x(23).
03 filler pic x.


PROCEDURE DIVISION.
MY_MAIN SECTION.
MAIN.
CALL "get_image_name_and_ident" USING image_identification.
DISPLAY "Image :", image-name.
DISPLAY "Ident :", image-ident.
DISPLAY "Linker:", linker-ident.
DISPLAY "Build :", build-ident.
DISPLAY "Linked:", link-time-text.
STOP RUN.

$
$ type IMAGE-IDENT-CALLING.COM
$ defin my_shared_stuff SYS$LOGIN:my_shared_stuff.exe
$ cc/deb/noopt GET_IDENT.C+sys$library:sys$lib_c.tlb/lib
$ link/debu/sysexe/share=my_shared_stuff GET_IDENT,sys$input:/opt
symbol_vector=(get_image_name_and_ident=procedure)
$
$ cob/debu/noopt IMAGE-IDENT-CALLING.COB
$ link/debu IMAGE-IDENT-CALLING, sys$input:/opt
my_shared_stuff/share
ident=some_string
build_ident=other_string
$
$ rename IMAGE-IDENT-CALLING.EXE TEST
$ run TEST
Image : IMAGE-IDENT-CALLING
Ident : SOME_STRING
Build : OTHER_STRING
Linked : 18-DEC-2006 16:50:04.41






Kay Dolle
Advisor

Re: ANALYZE/IMAGE callable interface?

Hi Hein van den Heuvel!
>>Is this for the purpose of obtaining the image ident for the current image?<<
Yes it is!
You wrote:
>>For ALPHA ... and if you are willing to link /sysexe without actually calling system stuff, or willing to hardcode a defintion of MMG$IMGHDRBUF to be 7FFCF800 you can use the code I wrote below. I wrote the example for intended cobol usage in a shareable library.<<
Thanks for your example. It's nearly what i neet, but does ist run also in IA64 and ist there any way to avoid sharable image (linking)?
Best regards,
Kay
Hein van den Heuvel
Honored Contributor

Re: ANALYZE/IMAGE callable interface?

Hi Hein van den Heuvel!
>>Is this for the purpose of obtaining the image ident for the current image?<<
Yes it is!

Then there could/should be an other alternative but I haven't figured it out for I64.
Any images is activated with 6 argument, the 3rd one pointing to the image header, the 4th leading to he image file descriptor.
Works fine to get the ident on Alpha without any sys calls, if you are the main routine.
On I64, while the image descriptor is still there, the header argument is 0. :-(

This is documented in the "OpenVMS Alpha Internals, scheduling and process control" book chapter 11.5.3 "Image activation by a CLI"

Too bad for you that they did not fake that to be similar to Alpha. For the world at large that may be the right thing as few folks know how to use this and we don't need any image activation slow downs.

>> Thanks for your example. It's nearly what i neet, but does ist run also in IA64 and ist there any way to avoid sharable image

No need for the shareable, you can just link main + service. The shareable example was extra as cobol folks (no disrespect intended :-) do not always know how to use those.

No, it does not work under I64. Sorry.
I tried for a short while, but it looks like real work to figure that one out, so until someone pays me for that or I get a lot of play time' I can not help with that.

On I64 the system function IMG$ELF_DECODE_IHD might be of help. Not sure yet.

Good luck!
Hein.



Hoff
Honored Contributor

Re: ANALYZE/IMAGE callable interface?

From within a program, there's unfortunately no supported interface to get at this stuff that I'm aware of. OpenVMS V8.2 did get some image-related flag interfaces (SET and SHOW IMAGE), but these don't show the image id and related information.

I usually embed the version details into the image using a linker option file -- or more commonly using a procedure which builds a linker options file. Based on a central data store containing the version information, I generate and set the image identification values and I set a couple of external symbols, and off I go.

ANALYZE/IMAGE (which can itself generate DCL symbols on current releases, BTW) sees the traditional values and fields from the image header (from the options file identification), and the application code can use the application-defined values (from the external symbols), the (because of the link-related procedures) the symbols and versions stay in synch, and no undocumented or non-portable interfaces are used.

Stephen Hoffman
HoffmanLabs
John Reagan
Respected Contributor

Re: ANALYZE/IMAGE callable interface?

I have I64 examples to retrieve the image information (it is scattered around the .EXE file). I'll post it next.
John Reagan
Respected Contributor

Re: ANALYZE/IMAGE callable interface?

// File: elf_imginfo.c
// Author: Hartmut Becker
// Creation Date: 24-Sep-2004
//
// Follow the Elf structure and print some VMS image note entries.
//

#include
#include
#include
#include

#include
#include

#define perrno(s) printf ("%s, errno: %d vaxc$errno: %%X%x\n", s, errno, vaxc$errno)

extern sys$asctim() ;

int format_note_section (char *filename) ;

static void decode_note_entries (char *section, int size) ;

static const char magic_plus[] = {
EHDR$K_ELFMAG0, EHDR$K_ELFMAG1, EHDR$K_ELFMAG2, EHDR$K_ELFMAG3,
EHDR$K_ELFCLASS64, EHDR$K_ELFDATA2LSB } ;

int main (int argc, char *argv[]) {
if (argc==1)
return printf ("-e-insarg, supply an ELF file.\n"), EXIT_FAILURE ;
if (format_note_section (argv[1]))
return EXIT_SUCCESS ;
return EXIT_FAILURE ;
}

int format_note_section (char *filename) {
FILE *fd ;
ELF64_EHDR the_elf_header ;
ELF64_SHDR *sh = NULL ;
char *section = NULL ;
int i ;

fd = fopen (filename, "rb") ;
if (!fd)
return perrno("-e-openerr"), 0 ;

if (fseek(fd, 0, SEEK_SET)!=0)
return perrno("-e-elfhdr"), 0 ;

if (fread(&the_elf_header, sizeof the_elf_header, 1, fd)!=1)
return perrno("-e-readehdr"), 0 ;

if (0!=strncmp((char*)&the_elf_header.ehdr$t_e_ident, magic_plus, sizeof magic_plus-1)) {
fclose (fd) ;
printf ("-e-dunno, don't understand this file format\n") ;
return 0 ;
}

sh = (ELF64_SHDR*) malloc (sizeof *sh *the_elf_header.ehdr$w_e_shnum) ;
if (fseek(fd, the_elf_header.ehdr$q_e_shoff, SEEK_SET)!=0)
return perrno("-e-seekshdr"), 0 ;
if (fread(sh, sizeof *sh*the_elf_header.ehdr$w_e_shnum, 1, fd)!=1)
return perrno("-e-readshdr"), 0 ;

for (i=1; i if (sh[i].shdr$l_sh_type==SHDR$K_SHT_NOTE) {
section = malloc (sh[i].shdr$q_sh_size) ;
if (fseek(fd, sh[i].shdr$q_sh_offset, SEEK_SET)!=0)
return perrno("-e-seeksec"), 0 ;
if (fread(section, sh[i].shdr$q_sh_size, 1, fd)!=1)
return perrno("-e-readsec"), 0 ;
decode_note_entries (section, sh[i].shdr$q_sh_size) ;
break ;
}

if (fclose(fd)!=0)
return perrno("-e-closerr"), 0 ;

return i }

static void decode_note_entries (char *section, int size) {
ELF64_NHDR *nh ;
char *owner;
char *entry;
for (nh = (ELF64_NHDR*)section ; (char*)nh-section nh= (ELF64_NHDR*)((char*)nh+sizeof(ELF64_NHDR)+((nh->nhdr$q_nh_namesz+7)&~7)+((nh->nhdr$q_nh_descsz+7)&~7))) {
if (nh->nhdr$q_nh_namesz>0)
owner = (char*)nh+sizeof(ELF64_NHDR) ;
else owner = "" ;
if (nh->nhdr$q_nh_descsz>0) {
if (nh->nhdr$q_nh_type == NHDR$K_NT_VMS_LINKTIME) {
char timbuf[32] ;
$DESCRIPTOR (timbuf_d, timbuf) ;
short int timlen ;
sys$asctim (&timlen,&timbuf_d,(char*)nh+sizeof(ELF64_NHDR)+((nh->nhdr$q_nh_namesz+7)&~7) ,0) ;
printf ("owner: '%s', linktime: %.*s\n",owner, timlen, timbuf) ;
}
else {
switch (nh->nhdr$q_nh_type) {
case NHDR$K_NT_VMS_IMGNAM:
entry = "imgnam" ;
break ;
case NHDR$K_NT_VMS_IMGID:
entry = "imgid" ;
break ;
case NHDR$K_NT_VMS_GSTNAM:
entry = "gstnam" ;
break ;
case NHDR$K_NT_VMS_IMGBID:
entry = "imgbid" ;
break ;
case NHDR$K_NT_VMS_LINKID:
entry = "linkid" ;
break ;
default:
entry = NULL ;
break ;
}
if (entry)
printf ("owner: '%s', %s: '%s'\n", owner, entry,
(char*)nh+sizeof(ELF64_NHDR) +((nh->nhdr$q_nh_namesz+7)&~7) ) ;
}
}
}
}
John Reagan
Respected Contributor

Re: ANALYZE/IMAGE callable interface?

Ooops, I forgot to click "retain format" and I couldn't figure out how to edit/delete a post. Feh!

I'll post it again.

And to answer the other question on how to get the image id of the current image... Since the ID isn't in the image header but rather contained in a ".note" buried somewhere in the image file, I don't think it is easily findable without reading the .EXE file.

// File: elf_imginfo.c
// Author: Hartmut Becker
// Creation Date: 24-Sep-2004
//
// Follow the Elf structure and print some VMS image note entries.
//

#include
#include
#include
#include

#include
#include

#define perrno(s) printf ("%s, errno: %d vaxc$errno: %%X%x\n", s, errno, vaxc$errno)

extern sys$asctim() ;

int format_note_section (char *filename) ;

static void decode_note_entries (char *section, int size) ;

static const char magic_plus[] = {
EHDR$K_ELFMAG0, EHDR$K_ELFMAG1, EHDR$K_ELFMAG2, EHDR$K_ELFMAG3,
EHDR$K_ELFCLASS64, EHDR$K_ELFDATA2LSB } ;

int main (int argc, char *argv[]) {
if (argc==1)
return printf ("-e-insarg, supply an ELF file.\n"), EXIT_FAILURE ;
if (format_note_section (argv[1]))
return EXIT_SUCCESS ;
return EXIT_FAILURE ;
}

int format_note_section (char *filename) {
FILE *fd ;
ELF64_EHDR the_elf_header ;
ELF64_SHDR *sh = NULL ;
char *section = NULL ;
int i ;

fd = fopen (filename, "rb") ;
if (!fd)
return perrno("-e-openerr"), 0 ;

if (fseek(fd, 0, SEEK_SET)!=0)
return perrno("-e-elfhdr"), 0 ;

if (fread(&the_elf_header, sizeof the_elf_header, 1, fd)!=1)
return perrno("-e-readehdr"), 0 ;

if (0!=strncmp((char*)&the_elf_header.ehdr$t_e_ident, magic_plus, sizeof magic_plus-1)) {
fclose (fd) ;
printf ("-e-dunno, don't understand this file format\n") ;
return 0 ;
}

sh = (ELF64_SHDR*) malloc (sizeof *sh *the_elf_header.ehdr$w_e_shnum) ;
if (fseek(fd, the_elf_header.ehdr$q_e_shoff, SEEK_SET)!=0)
return perrno("-e-seekshdr"), 0 ;
if (fread(sh, sizeof *sh*the_elf_header.ehdr$w_e_shnum, 1, fd)!=1)
return perrno("-e-readshdr"), 0 ;

for (i=1; i if (sh[i].shdr$l_sh_type==SHDR$K_SHT_NOTE) {
section = malloc (sh[i].shdr$q_sh_size) ;
if (fseek(fd, sh[i].shdr$q_sh_offset, SEEK_SET)!=0)
return perrno("-e-seeksec"), 0 ;
if (fread(section, sh[i].shdr$q_sh_size, 1, fd)!=1)
return perrno("-e-readsec"), 0 ;
decode_note_entries (section, sh[i].shdr$q_sh_size) ;
break ;
}

if (fclose(fd)!=0)
return perrno("-e-closerr"), 0 ;

return i }

static void decode_note_entries (char *section, int size) {
ELF64_NHDR *nh ;
char *owner;
char *entry;
for (nh = (ELF64_NHDR*)section ; (char*)nh-section nh= (ELF64_NHDR*)((char*)nh+sizeof(ELF64_NHDR)+((nh->nhdr$q_nh_namesz+7)&~7)+((nh->nhdr$q_nh_descsz+7)&~7))) {
if (nh->nhdr$q_nh_namesz>0)
owner = (char*)nh+sizeof(ELF64_NHDR) ;
else owner = "" ;
if (nh->nhdr$q_nh_descsz>0) {
if (nh->nhdr$q_nh_type == NHDR$K_NT_VMS_LINKTIME) {
char timbuf[32] ;
$DESCRIPTOR (timbuf_d, timbuf) ;
short int timlen ;
sys$asctim (&timlen,&timbuf_d,(char*)nh+sizeof(ELF64_NHDR)+((nh->nhdr$q_nh_namesz+7)&~7) ,0) ;
printf ("owner: '%s', linktime: %.*s\n",owner, timlen, timbuf) ;
}
else {
switch (nh->nhdr$q_nh_type) {
case NHDR$K_NT_VMS_IMGNAM:
entry = "imgnam" ;
break ;
case NHDR$K_NT_VMS_IMGID:
entry = "imgid" ;
break ;
case NHDR$K_NT_VMS_GSTNAM:
entry = "gstnam" ;
break ;
case NHDR$K_NT_VMS_IMGBID:
entry = "imgbid" ;
break ;
case NHDR$K_NT_VMS_LINKID:
entry = "linkid" ;
break ;
default:
entry = NULL ;
break ;
}
if (entry)
printf ("owner: '%s', %s: '%s'\n", owner, entry,
(char*)nh+sizeof(ELF64_NHDR) +((nh->nhdr$q_nh_namesz+7)&~7) ) ;
}
}
}
}