DealingwithmissingsystemcallorioctlwrappersinValgrind
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You'reprobablyreadingthisbecauseValgrindbombedoutwhilst
runningyourprogram,andadvisedyoutoreadthisfile.Thegood
newsisthat,ingeneral,it'seasytowritethemissingsyscallor
ioctlwrappersyouneed,sothatyoucancontinueyourdebugging.If
yousendtheresultingpatchestome,thenyou'llbedoingafavourto
allfutureValgrinduserstoo.
Notethatan"ioctl"isjustaspecialkindofsystemcall,really;so
there'snotalotofneedtodistinguishthem(atleastconceptually)
inthediscussionthatfollows.
Allthismachineryisincoregrind/m_syswrap.
Whataresyscall/ioctlwrappers?Whatdotheydo?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Valgrinddoeswhatitdoes,inpart,bykeepingtrackofeverythingyour
programdoes.Whenasystemcallhappens,forexamplearequesttoread
partofafile,controlpassestotheLinuxkernel,whichfulfillsthe
request,andreturnscontroltoyourprogram.Theproblemisthatthe
kernelwilloftenchangethestatusofsomepartofyourprogram'smemory
asaresult,andtools(instrumentationplug-ins)mayneedtoknowabout
this.
Syscallandioctlwrappershavetwojobs:
1.Tellatoolwhat'sabouttohappen,beforethesyscalltakesplace.A
toolcouldperformchecksbeforehand,eg.ifmemoryabouttobewritten
isactuallywriteable.Thispartisuseful,butnotstrictly
essential.
2.Tellatoolwhatjusthappened,afterasyscalltakesplace.Thisis
soitcanupdateitsviewoftheprogram'sstate,eg.thatmemoryhas
justbeenwrittento.Thisstepisessential.
The"happenings"mostlyinvolvereading/writingofmemory.
So,let'slookatanexampleofawrapperforasystemcallwhich
shouldbefamiliartomanyUnixprogrammers.
Thesyscallwrapperfortime()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thewrapperforthetimesystemcalllookslikethis:
PRE(sys_time)
{
/*time_ttime(time_t*t);*/
PRINT("sys_time(%p)",ARG1);
PRE_REG_READ1(long,"time",int*,t);
if(ARG1!=0){
PRE_MEM_WRITE("time(t)",ARG1,sizeof(vki_time_t));
}
}
POST(sys_time)
{
if(ARG1!=0){
POST_MEM_WRITE(ARG1,sizeof(vki_time_t));
}
}
Thefirstthingwedohappensbeforethesyscalloccurs,inthePRE()function.
ThePRE()functiontypicallystartswithinvokingtothePRINT()macro.This
PRINT()macroimplementssupportforthe--trace-syscallscommandlineoption.
Next,thetoolistoldthereturntypeofthesyscall,thatthesyscallhas
oneargument,thetypeofthesyscallargumentandthattheargumentisbeing
readfromaregister:
PRE_REG_READ1(long,"time",int*,t);
Next,ifanon-NULLbufferispassedinastheargument,tellthetoolthatthe
bufferisabouttobewrittento:
if(ARG1!=0){
PRE_MEM_WRITE("time",ARG1,sizeof(vki_time_t));
}
Finally,thereallyimportantbit,afterthesyscalloccurs,inthePOST()
function:if,andonlyif,thesystemcallwassuccessful,tellthetoolthat
thememorywaswritten:
if(ARG1!=0){
POST_MEM_WRITE(ARG1,sizeof(vki_time_t));
}
ThePOST()functionwon'tbecalledifthesyscallfailed,soyou
don'tneedtoworryaboutcheckingthatinthePOST()function.
(Note:thisissometimesabug;somesyscallsdoreturnresultswhen
they"fail"-forexample,nanosleepreturnstheamountofunslept
timeifinterrupted.TODO:addanotherper-syscallflagforthis
case.)
Notethatweusethetype'vki_time_t'.Thisisacopyofthekernel
type,with'vki_'prefixed.Ourcopiesofsuchtypesarekeptinthe
appropriatevki*.hfile(s).Wedon'tincludekernelheadersorglibcheaders
directly.
Writingyourownsyscallwrappers(seebelowforioctlwrappers)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IfValgrindtellsyouthatsystemcallNNNisunimplemented,dothe
following:
1.Findoutthenameofthesystemcall:
grepNNN/usr/include/asm/unistd*.h
Thisshouldtellyousomethinglike__NR_mysyscallname.
Copythisentrytoinclude/vki/vki-scnums-$(VG_PLATFORM).h.
2.Do'man2mysyscallname'togetsomeideaofwhatthesyscall
does.Notethattheactualkernelinterfacecandifferfromthis,
soyoumightalsowanttocheckaversionoftheLinuxkernel
source.
NOTE:anysyscallwhichhassomethingtodowithsignalsor
threadsisprobably"special",andneedsmorecarefulhandling.
Postsomethingtovalgrind-developersifyouaren'tsure.
3.Addacasetothealready-hugecollectionofwrappersin
thecoregrind/m_syswrap/syswrap-*.cfiles.
Foreachin-memoryparameterwhichisreadorwrittenby
thesyscall,dooneof
PRE_MEM_READ(...)
PRE_MEM_RASCIIZ(...)
PRE_MEM_WRITE(...)
forthatparameter.Thendothesyscall.Then,ifthesyscall
succeeds,issuesuitablePOST_MEM_WRITE(...)calls.
(There'snoneedforPOST_MEM_READcalls.)
Also,addittothesyscall_table[]array;useoneofGENX_,GENXY
LINX_,LINXY,PLAX_,PLAXY.
GEN*forgenericsyscalls(insyswrap-generic.c),LIN*forlinux
specificones(insyswrap-linux.c)andPLA*fortheplatform
dependentones(insyswrap-$(PLATFORM)-linux.c).
The*XYvariantifitrequiresaPRE()andPOST()function,and
the*X_variantifitonlyrequiresaPRE()
function.
Ifyoufindthisdifficult,readthewrappersforothersyscalls
forideas.Agoodtipistolookforthewrapperforasyscall
whichhasasimilarbehaviourtoyours,anduseitasa
startingpoint.
Ifyouneedstructuredefinitionsand/orconstantsforyoursyscall,
copythemfromthekernelheadersintoinclude/vki.handco.,with
theappropriatevki_*/VKI_*namemangling.Don't#includeany
kernelheaders.Andcertainlydon't#includeanyglibcheaders.
Testit.
NotethatacommonerroristocallPOST_MEM_WRITE(...)
with0(NULL)asthefirst(address)argument.Thisusuallymeans
yourlogicisslightlyinadequate.It'sasufficientlycommonbug
thatthere'sabuilt-incheckforit,andyou'llgeta"probably
sanitycheckfailure"forthesyscallwrapperyoujustmade,ifthis
isthecase.
4.Oncehappy,sendusthepatch.Prettyplease.
Writingyourownioctlwrappers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Isprettymuchthesameaswritingsyscallwrappers,exceptthatall
theactionhappenswithinPRE(ioctl)andPOST(ioctl).
There'sadefaultcase,sometimesitisn'tcorrectandyouhavetowritea
morespecificcasetogettherightbehaviour.
Asabove,pleasecreateabugreportandattachthepatchasdescribed
onhttp://www.valgrind.org.
Writingyourowndoorcallwrappers(Solarisonly)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlikesyscallsorioctls,doorcallstransferdatabetweentwouserspace
programs,albeitthroughakernelinterface.Programsmayusecompletely
proprietarysemanticsinthedatabufferspassedbetweenthem.
Thereforeitmaynotbepossibletocapturethesesemanticswithin
aValgrinddoorcallordoorreturnwrapper.
Nevertheless,forsystemorwell-knowndoorservicesitwouldbebeneficial
tohaveadoorcallandadoorreturnwrapper.Writingsuchwrapperispretty
muchthesameaswritingioctlwrappers.Pleasetakeafewmomentstostudy
thefollowingpicturedepictinghowadoorclientandadoorserverinteract
throughthekernelinterfaceinatypicalscenario:
doorclientthreadkerneldoorserverthread
invokesdoor_call()invokesdoor_return()
-------------------------------------------------------------------
<----PRE(sys_door,DOOR_RETURN)
PRE(sys_door,DOOR_CALL)--->
---->POST(sys_door,DOOR_RETURN)
---->server_procedure()
<----
<----PRE(sys_door,DOOR_RETURN)
POST(sys_door,DOOR_CALL)<---
ThefirstPRE(sys_door,DOOR_RETURN)isinvokedwithdata_ptr=NULL
anddata_size=0.That'sbecauseithasnotreceivedanydatafrom
adoorcall,yet.
Semanticsaredescribedbythefollowingfunctions
incoregring/m_syswrap/syswrap-solaris.cmodule:
oForadoorcallwrapperthefollowingattributesof'params'argument:
-data_ptr(andassociateddata_size)asinputbuffer(request);
describedindoor_call_pre_mem_params_data()
-rbuf(andassociatedrsize)asoutputbuffer(response);
describedindoor_call_post_mem_params_rbuf()
oForadoorreturnwrapperthefollowingparameters:
-data_ptr(andassociateddata_size)asinputbuffer(request);
describedindoor_return_post_mem_data()
-data_ptr(andassociateddata_size)asoutputbuffer(response);
describedindoor_return_pre_mem_data()
There'sadefaultcasewhichmaynotbecorrectandyouhavetowritea
morespecificcasetogettherightbehaviour.UnlessValgrind'soption
'--sim-hints=lax-doors'isspecified,thedefaultcasealsospitsawarning.
Asabove,pleasecreateabugreportandattachthepatchasdescribed
onhttp://www.valgrind.org.