[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers

Title:** Hackers **
Moderator:XDELTA::HOFFMAN
Created:Mon Feb 01 1988
Last Modified:Tue May 27 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1838
Total number of notes:13578

1832.0. "ldr$unload_image" by CPEEDY::BRADLEY (Chuck Bradley) Tue Mar 25 1997 18:08

have any of you ever used ldr$unload_image?
do you know anyone or any project that might have tried it?

do any of you have any hints or warnings about replacing 
an execlet on the fly?

thanks.
T.RTitleUserPersonal
Name
DateLines
1832.1ZIMBRA::BERNARDODave Bernardo, VMS EngineeringWed Mar 26 1997 00:096
    
    ldr$unload_image can only unload an execlet which was previously
    loaded so that it _could_ be unloaded.... so, how are you planning
    to use it?
    
    d.
1832.2EEMELI::MOSEROrienteers do it in the bush...Wed Mar 26 1997 09:249
    I persoanlly have done this when writing an execlet and testing it,
    so I didn't have to reboot every time, but there are gotchas you need
    to know, otherwise you trigger an automatic reboot (== bugcheck).
    
    I do not recommend that for a production environment, and as Dave said
    you need to load it correctly so you can use the unload. I'll post my
    load/unload hack in the next reply (saince this is hackers...)
    
    /cmos
1832.3EEMELI::MOSEROrienteers do it in the bush...Wed Mar 26 1997 09:26235
1832.4considering trying itCPEEDY::BRADLEYChuck BradleyWed Mar 26 1997 14:1526
re .1, what am i trying to do?

similar to .2, we could save a lot of time testing if we could unload
an execlet.  in pathworks, we have an execlet to implement streams
and we use it for various communications protocols.  we build several
times per week and each new installation requires a reboot. it would
be nice to avoid the reboot.  

some customers report problems, and sometimes we have to collect more
information to solve the problem. sometimes it takes an instrumented
version of the software to gather the information.  the customer does
not want to reboot just to gather information, so he waits until the
next scheduled or accidental downtime to install the instrumented
software.  as a result it takes a longer time to solve the problem.
CLD turnaround time is a major concern this year.

someone worked on this for a while, but did not have a full solution
when they left the company.  i wanted to be sure it was possible
before looking further.  ldr$unload_image does not seem to be documented
for the outside world, so it was easy to imagine that it was only
half implemented.  the existence proof in .3 is reassuring.

re .3, sample of use:
thank you.  after i study it, and review what has been done here,
i may have some more questions.

1832.5Suggestions, Pointers...XDELTA::HOFFMANSteve, OpenVMS EngineeringWed Mar 26 1997 15:0613
   There are some ldr$* and *image* keywords here...

   Have you considered an execlet that contains vector(s) to the real
   execlet(s)?  This would let you "update" the code on the fly.  (You
   might not be able to unload the code, but generating pool large
   enough to support some no-longer-needed code might be easier than
   the reboot appears to be.)

   My preference is usually to use a pseudo device driver as a "shell"
   for loadable code, as one can easily add more of these, and one has
   a nice user-mode-accessable "control interface" available.

1832.6thanks. lots of pool usedCPEEDY::BRADLEYChuck BradleyWed Mar 26 1997 16:5624
re .5:
thanks for the suggested keywords.  i'll check them out.
so few conferences have useful and up to date keywords, that i didn't 
even try.  i made about a half dozen tries with dir/title=foo and found 
very little -- unloading a device driver, repeated initialization.
so i scanned the entire directory looking for related titles.
when i didn't see anything useful, i entered .0.

we might be able to afford losing the space occupied by the image to
be replaced, but i think there is many times that much in data buffers.
this is just a hunch, not an estimate or even an educated guess,
but i suspect doing it as bad as i can get away with is at least
3/4 of the effort to do it right.

i'll also look at the pseudo device driver.  i've only looked at
a tiny fraction of the code, but that part is well organized.
all of the allocated pool is on multiple lists and it looks
like i can give it all back exactly once.

thanks, again for the suggestions and the pointers.

BTW, silence here does not necessarily mean success. this might not
even make it to the top of the list of things to work on.
1832.7ZIMBRA::BERNARDODave Bernardo, VMS EngineeringWed Mar 26 1997 21:2517
    If you decide to go the unload route, you'll need to initially load
    your execlets with the LDR$V_UNL bit set. And, you will also have to
    make sure that nothing is using the execlet while you are trying to
    unload it... or you'll get to see the reboot feature of the ldr
    routines in action.

    One of the features execlets were intended to have were unload
    routines. Similar to initialization routines but at the other end of
    the rainbow. So, you _could_ try to use this feature to deallocate your
    memory.  But, you will probably be the first. I own the exec loader on
    Alpha VMS and I know that everything else works. But, no one uses the
    unload routine stuff, so I can't say if it does.

    And lastly, the ldr$ routines got documented in V7.1... in the
    Programming Concepts book.

    d.
1832.8It can be done....UTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:3921
    Well, you can load as well as unload. Some time ago i created some
    stuff to load and unload a module on the fly. The main routine to do
    the processing is called from macro and written in C, it was some
    process state monitor. The problem i ran into was that real dynamic
    unloading support is not compiled in the VMS kernel. I don't have the
    right details in my head, but you should be able to specify an unload
    routine in a seprarate psect, and by specifying a flag it should be
    called. But this code is currently not included in the kernel.
    
    The next replies contain example code.
    
    .+1 = BUILD.COM, the build procedure
    .+2 = ARCH.MAR, used for conditional compilation for Vax or Alpha
    .+3 = SMON.MAR, the main routine
    .+4 = SMONLOAD.C, the dynamic loader
    .+5 = SMONUNLOAD.C, the dynamic unloader
    .+6 = PROCPROC.C, the C routine called by the main routine to do
    some processing.
    
    Jur.
    
1832.9BUILD.COMUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:3993
$ if f$getsyi("hw_model") .gt. 1023
$ then
$   alpha = 1
$ else
$   alpha = 0
$ endif
$ if alpha
$ then
$   if p1 .nes. "" then goto linka
$   macro/obj=smon arch+smon+sys$library:lib/lib
$   cc/define="ALPHA"/instruct=nofloat/extern=strict-
/warning=disable=globalext procproc+sys$library:sys$lib_c/lib
$   cc/define="ALPHA" smonload+sys$library:sys$lib_c/lib
$   cc/define="ALPHA" smonunload+sys$library:sys$lib_c/lib
$linka:
$   link/notrace/sysexe smonload
$   link/notrace/sysexe smonunload
$   link/native_only/bpages=14/section/replace/notraceback/nosysshr/vms_exec-
	/nodemand_zero/contiguous/share=smon.exe/map=smon/cross/full sys$input:/opt
cluster=smon,,,smon,procproc,sys$library:starlet/include=(sys$doinit)
sys$loadable_images:sys$base_image.exe/share/sele
psect_attr = $linkage                   ,  PIC,GBL,NOSHR,NOEXE,  RD,  WRT
psect_attr = exec$init_linkage          ,  PIC,USR,CON,REL,GBL,NOSHR,EXE,RD,WRT,NOVEC
psect_attr = exec$init_code             ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_000              ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_001              ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_002              ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_sstbl_000        ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_sstbl_001        ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = exec$init_sstbl_002        ,  PIC,GBL,NOSHR,  EXE,  RD,  WRT
psect_attr = $link$			,  PIC,WRT
psect_attr = $initial$			,  PIC,WRT
psect_attr = $literal$			,  PIC,NOSHR,WRT
psect_attr = $readonly$			,  PIC,NOSHR,WRT
psect_attr = $code$			,  PIC,GBL,NOSHR,  EXE,  RD,  NOWRT
psect_attr = $data$			,  PIC,GBL,NOSHR,  NOEXE,  RD,  WRT
psect_attr = $bss$			,  PIC,GBL,NOSHR,  NOEXE,  RD,  WRT
collect = nonpaged_readonly_psects/attributes=resident,-
	exec$nonpaged_code,$code$
collect = nonpaged_readwrite_psects/attributes=resident,-
	exec$nonpaged_data,$data$,$link$,$literal$,$bss$,-
	$readonly$,$linkage,exec$nonpaged_linkage
collect = initialization_psects/attributes=initialization_code -
        , exec$init_code -
        , exec$init_000 -
        , exec$init_001 -
        , exec$init_002 -
        , exec$init_linkage -
        , exec$init_sstbl_000 -
        , exec$init_sstbl_001 -
        , exec$init_sstbl_002
$ else
$   if p1 .nes. "" then goto linkv
$   macro smon+sys$library:lib/lib
$   cc procproc
$   cc smonload
$   cc smonunload
$linkv:
$   link/notrace smonload,sys$input/opt
sys$share:vaxcrtl.exe/share
sys$system:sys.stb/selective
$   link/notrace smonunload,sys$input/opt
sys$share:vaxcrtl.exe/share
sys$system:sys.stb/selective
$   link/nosysshr/notraceback/share=smon/contiguous-
/symbol=smon/map=smon/full/cross sys$input/opt
sys$library:starlet/include:(sys$doinit),-
sys$disk:[]smon,procproc,-
sys$system:sys.stb/selective
vector_table=sys$system:sys.stb
psect_attr=$code,noshr
psect_attr=$char_string_constants,noshr
collect=nonpaged_readonly_psects/attributes=resident,-
	exec$nonpaged_code,$code
collect=nonpaged_readwrite_psects/attributes=resident,-
	exec$nonpaged_data,$data,$char_string_constants
collect=paged_readonly_psects,-
	exec$paged_code
collect=paged_readwrite_psects,-
	exec$paged_data
collect=initialization_psects/attributes=initialization_code,-
	exec$init_code,-
	exec$init_000,-
	exec$init_001,-
	exec$init_002,-
	exec$init_pfntbl_001,-
	exec$init_pfntbl_002,-
	exec$init_pfntbl_003,-
	exec$init_sstbl_000,-
	exec$init_sstbl_001,-
	exec$init_sstbl_002
$ endif
$ copy/log smon.exe sys$common:[sys$ldr]
1832.10ARCH.MARUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:401
alpha==1
1832.11SMON.MARUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:40116
	.title		Smon - Process state monitor
	.ident		/V1.0/
	.library	'sys$library:lib'

	$ipldef
      	$tqedef
	$ldrimgdef
	$inirtndef      
	.if df alpha
	$ldrdef
	.endc

	.macro	return
	.if df alpha
	ret
	.iff
	rsb
	.endc
	.endm

	DECLARE_PSECT	EXEC$INIT_CODE

	.if df alpha
	INITIALIZATION_ROUTINE	NAME=SMON$INIT
	.iff
	INITIALIZATION_ROUTINE	NAME=SMON$INIT,-
				SYSTEM_RTN=1
	.endc
;
; Input: R4 = LDRIMG block
;        R5 = Address of flags longword
;	 R0,R1,R2,R3 = scratch
;
smon$init:
	.if df alpha
	.call_entry	input=<r4,r5>,-
			output=<r0>
	.endc
	movzwl	#ss$_normal,r0
	bbs	#inirtn$v_called,(r5),20$
	setipl	#ipl$_astdel,-                                  
		environ=uniprocessor			; Avoid scheduling
;
; Now allocate the TQE and queue it to the system.
;                                                 
	pushr	#^m<r2,r3,r4,r5>
	jsb	g^exe$alloctqe		  		; Allocate a timer entry
	blbc	r0,10$					; Any errors ?
	movl	r2,tqeadr
;
; Now setup the TQE to contain the correct parameters.
;                
	movab	action,tqe$l_fpc(r2)			; Setup the rtn address
	movb	#tqe$c_ssrept,tqe$b_rqtype(r2)		; Make it repeatable
	movl	r2,r5	       				; Copy the TQE address
	movq	g^exe$gq_systime,r0			; Get current time
	.iif df alpha, .disable flagging
	movq	#^D1000000,tqe$q_delta(r5)		; 10 Ms delta time
	.iif df alpha, .enable flagging
	jsb	g^exe$instimq				; Insert it in the queue
	movab	smon$unload,unlvec			; Setup address of unload routine
	.if ndf alpha
	bisl2	#inirtn$m_sysrtn,unlvec+4
	.endc
	moval	unlvec,ldrimg$l_unlvec(r4)		; Setup address of unload vector
	movzwl	#ss$_normal,r0

10$:	setipl	#0,-          
	       	environ=uniprocessor			; Restore IPL
	popr	#^m<r2,r3,r4,r5>

20$:	blbc	r0,30$					; Stop in case of error
	calls	#0,procinit				; Init of main code

30$:	return						; Return to the caller

	DECLARE_PSECT	EXEC$NONPAGED_CODE

action:
	.if df alpha
	.call_entry
	.endc

	lock	sched
	calls	#0,procproc
	unlock	sched
	return
;
smon$unload:
	.if df alpha
	.call_entry	output=<r0>
	.endc

	movl	tqeadr,r4
	jsb	g^exe$rmvtimq
	blbc	r0,10$
	movl	r4,r0
	jsb	g^exe$deanonpaged
	movzwl	#ss$_normal,r0

10$:	return

	DECLARE_PSECT	EXEC$NONPAGED_DATA

tqeadr:		.long	0				; Our TQE address

unlvec:		.long	0				; Unload routine address
		.long	0				; Flags
		.long	0				; Termination of chain

;	DECLARE_PSECT	EXEC$UNL_001
;
;	.address	smon$unload
;	.long		0

	.end
1832.12SMONLOAD.CUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:4073
#include <stdio.h>
#include <descrip.h>
#include <psldef.h>
#include <lnmdef.h>
#include <starlet.h>
#include <lib$routines.h>

#define IMAGE "SMON.EXE"
#define TABLE "LNM$SYSTEM_TABLE"
#define LOGNAM "SMON$HANDLE"

#ifdef ALPHA
#include <ldrdef.h>
#else
#ifndef LDR_DYN$M_UNL
#define LDR_DYN$M_UNL 2
#endif
#endif

typedef struct itmlst {
	short size;
	short item;
	char *buffer;
	char *retlen;
} ITEMS;

int ldr$load_image();

int main()
{
	int stat;
	unsigned int handle[3];
	unsigned int arglist[4];
	$DESCRIPTOR(imgdsc,IMAGE);
	$DESCRIPTOR(tblname,TABLE);
	$DESCRIPTOR(logname,LOGNAM);
	ITEMS lnmlst[4];
	char h1[9], h2[9], h3[9];

	arglist[0] = 3;
	arglist[1] = (int) &imgdsc;
#ifdef ALPHA
	arglist[2] = LDR$M_UNL;
#else
	arglist[2] = LDR_DYN$M_UNL;
#endif
	arglist[3] = (int) handle;
	stat = sys$cmkrnl(&ldr$load_image,arglist);
	if (!(stat & 1))
		lib$stop(stat);
	printf("Image %s loaded successfully.\nAddress:\t%08.8X\nLDRIMG block:\t%08.8X\nSeq. number:\t%08.8X\n",
		IMAGE, handle[0], handle[1], handle[2]);
	sprintf(h1,"%08.8X",handle[0]);
	sprintf(h2,"%08.8X",handle[1]);
	sprintf(h3,"%08.8X",handle[2]);
	lnmlst[0].size = 8;
	lnmlst[0].item = LNM$_STRING;
	lnmlst[0].buffer = h1;
	lnmlst[0].retlen = 0;
	lnmlst[1].size = 8;
	lnmlst[1].item = LNM$_STRING;
	lnmlst[1].buffer = h2;
	lnmlst[1].retlen = 0;
	lnmlst[2].size = 8;
	lnmlst[2].item = LNM$_STRING;
	lnmlst[2].buffer = h3;
	lnmlst[2].retlen = 0;
	lnmlst[3].size = 0;
	lnmlst[3].item = 0;
	stat = sys$crelnm(0,&tblname,&logname,&PSL$C_EXEC,&lnmlst);
	if (!(stat & 1))
		lib$stop(stat);
}
1832.13SMONUNLOAD.CUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:4081
#include <stdio.h>
#include <descrip.h>
#include <psldef.h>
#include <lnmdef.h>
#include <starlet.h>
#include <lib$routines.h>

#define IMAGE "SMON.EXE"
#define TABLE "LNM$SYSTEM_TABLE"
#define LOGNAM "SMON$HANDLE"

typedef struct itmlst {
	short size;
	short item;
	char *buffer;
	short *retlen;
} ITEMS;

int ldr$unload_image();

int main()
{
	int stat;
	unsigned int handle[3];
	unsigned int arglist[3];
	$DESCRIPTOR(imgdsc,IMAGE);
	$DESCRIPTOR(tblname,TABLE);
	$DESCRIPTOR(logname,LOGNAM);
	ITEMS lnmlst[7];
	char h1[9], h2[9], h3[9];
	short l1, l2, l3;
	int idx1, idx2, idx3;

	idx1 = 0;
	idx2 = 1;
	idx3 = 2;
	lnmlst[0].size = 4;
	lnmlst[0].item = LNM$_INDEX;
	lnmlst[0].buffer = (char *) &idx1;
	lnmlst[0].retlen = 0;
	lnmlst[1].size = 8;
	lnmlst[1].item = LNM$_STRING;
	lnmlst[1].buffer = h1;
	lnmlst[1].retlen = &l1;
	lnmlst[2].size = 4;
	lnmlst[2].item = LNM$_INDEX;
	lnmlst[2].buffer = (char *) &idx2;
	lnmlst[2].retlen = 0;
	lnmlst[3].size = 8;
	lnmlst[3].item = LNM$_STRING;
	lnmlst[3].buffer = h2;
	lnmlst[3].retlen = &l2;
	lnmlst[4].size = 4;
	lnmlst[4].item = LNM$_INDEX;
	lnmlst[4].buffer = (char *) &idx3;
	lnmlst[4].retlen = 0;
	lnmlst[5].size = 8;
	lnmlst[5].item = LNM$_STRING;
	lnmlst[5].buffer = h3;
	lnmlst[5].retlen = &l3;
	lnmlst[6].size = 0;
	lnmlst[6].item = 0;
	stat = sys$trnlnm(0,&tblname,&logname,&PSL$C_EXEC,&lnmlst);
	if (!(stat & 1))
		lib$stop(stat);
	h1[l1] = '\0';
	h2[l2] = '\0';
	h3[l3] = '\0';
	sscanf(h1,"%x",&handle[0]);
	sscanf(h2,"%x",&handle[1]);
	sscanf(h3,"%x",&handle[2]);
	arglist[0] = 2;
	arglist[1] = (int) &imgdsc;
	arglist[2] = (int) handle;
	stat = sys$cmkrnl(&ldr$unload_image,arglist);
	if (!(stat & 1))
		lib$stop(stat);
	stat = sys$dellnm(&tblname,&logname,&PSL$C_EXEC);
	if (!(stat & 1))
		lib$stop(stat);
}
1832.14PROCPROC.CUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:40137
#ifdef ALPHA
#include <pcbdef.h>
#else
typedef struct _pcb {
	char dummy1[26];
	unsigned short pcb$w_state;
	char dummy2[284];
	unsigned char pcb$t_lname[16];
} PCB;
#endif
#include <starlet.h>
#include <ssdef.h>

int p_strlen();
int p_strncmp();
char *p_strcpy();
void p_bzero();

globalref unsigned long int sch$gl_pcbvec;
globalref unsigned long int sch$gl_maxpix;

struct proctbl {
	char proclen;
	char procname[15];
	int statarray[15];
	int starttime[2];
};

static struct proctbl procs[1000];

static char *namtbl[] = {
	"PWRK$MASTER",
	"PWRK$LMSRV",
	"PWRK$LMMCP",
	"PWRK$LMDMN",
	"PWRK$ADMIN_0",
	"PWRK$LICENSE_R",
	"PWRK$KNBDAEMON",
	"PWRK$NBDAEMON",
	"PWRK$MONITOR",
	"NETBIOS",
	""
};

int procinit()
{
   struct proctbl *p;
   char **namp;
   int stat, starttime[2];

   if (sch$gl_maxpix > 1000)
      return (SS$_INSFMEM);
   stat = sys$gettim(starttime);
   if (stat & 1) {
      namp = namtbl;
      p = procs;
      for (; *namp[0]; p++, namp++) {
         p_strcpy(p->procname,*namp);
         p->proclen = p_strlen(p->procname);
         p_bzero(p->statarray,sizeof(p->statarray));
         p->starttime[0] = starttime[0];
         p->starttime[1] = starttime[1];
      }
      p->proclen = 0;
   }
   return stat;
}

int procproc()
{
   unsigned int maxindex, *tblpnt;
   PCB *pcbpnt, *nullpcb;
   struct proctbl *p;
   int j, namesize;

   maxindex = sch$gl_maxpix - 2;
   tblpnt = (unsigned int *) sch$gl_pcbvec;
   nullpcb = (PCB *) *tblpnt++;		/* pcb of null process */
   tblpnt++;				/* skip swapper */

   for (j = 0; j <= maxindex; j++) {
      pcbpnt = (PCB *) *tblpnt++;
      if (pcbpnt != nullpcb) {
         namesize = *pcbpnt->pcb$t_lname & 0xff;
         for (p = procs; p->proclen > 0; p++) {
            if ((p->proclen == namesize) &&
               (p_strncmp(pcbpnt->pcb$t_lname+1,p->procname,namesize) == 0)) {
#ifdef ALPHA
               p->statarray[pcbpnt->pcb$l_state]++;
#else
               p->statarray[pcbpnt->pcb$w_state]++;
#endif
            }
         }
      }
   }
   return 1;
}

int p_strncmp(s1, s2, n)
register unsigned char *s1, *s2;
register n;
{
   while (--n >= 0 && *s1 == *s2++)
      if (*s1++ == '\0')
         return(0);
   return(n<0 ? 0 : *s1 - *--s2);
}

char *p_strcpy(s1, s2)
register char *s1, *s2;
{
   register char *os1;

   os1 = s1;
   while (*s1++ = *s2++);
   return(os1);
}

int p_strlen(s)
register char *s;
{
   register n;

   n = 0;
   while (*s++)
      n++;
   return(n);
}

void p_bzero(p, n)
register char *p;
register n;
{
   while (--n >= 0)
      *p++ = 0;
}
1832.15More infoUTRTSC::VDBURGChange mode to PANICThu Mar 27 1997 04:506
    I found some reference to the unload problem:
    
    I link in the module SYS$DOINIT from STARLET.OLB, but for real dynamic
    unloading SYS$DOINIT_UNL is needed which is not provided.
    
    Jur.