From pregnenolone at asc-parkstad.nl Fri Oct 1 03:22:16 2010 From: pregnenolone at asc-parkstad.nl (Pesce Sipp) Date: Thu, 30 Sep 2010 20:22:16 -0700 Subject: this reason, your village has been polluted. But as you have now ki Message-ID: <4CA552B6.9070905@asc-parkstad.nl> The oak-god: "Here am I. I did as you bade me. But I did not find my wife." "Wait a moment," said the oak-god; "you do not know what a tumult has been caused by your visit to the sky, neither have I yet told you that it was a demon who stole your wife. This demon, looking up from hell below, was so much astonished to see and hear you riding up and down the streets of heaven singing, that his gaze is still fixed in that direction. I will profit hereby to go round quietly, while his attention is absorbed, and let your wife out of the box in which he keeps her shut up." The oak-god did as he had promised. He brought back the woman, and handed over both her and the gold horse to the man, saying: "Do not use this horse to make any more journeys to the sky. Stay on earth, and breed from it." The couple obeyed his commands, and became very rich. The gold horse gave birth to two horses, and these two bred likewise, till at last horses filled all the land of the Ainos.--(Written down from memory. Told by Ishanashte, 21st July, 1886.) xviii.--_The First Appearance of the Horse in Aino-land._ A very beautiful woman had a husband. He was a very skilful fellow -------------- next part -------------- A non-text attachment was scrubbed... Name: remanding.jpg Type: application/octet-stream Size: 11115 bytes Desc: not available URL: From favourtessy24 at yahoo.com Sat Oct 2 00:23:29 2010 From: favourtessy24 at yahoo.com (fred) Date: Sat, 2 Oct 2010 01:23:29 +0100 (BST) Subject: Hello Message-ID: <573477.67647.qm@web29716.mail.ird.yahoo.com> Hello dear, Good day how are you doing.my name is miss Favour Fred Tessy,well i saw your profile to day i am interested in you i will like to know more about you and what you are looking for in a relationship.please dear i want you to try get back to me with my E mail so that i will tell you more about me and give to you my photo for you to know more about me. Thanks fro your understand, my dear yours in love miss Favour Fred Tessy, Favourtessy24 at yahoo.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From favourtessy24 at yahoo.com Sat Oct 2 00:47:38 2010 From: favourtessy24 at yahoo.com (fred) Date: Sat, 2 Oct 2010 01:47:38 +0100 (BST) Subject: Hello Message-ID: <344550.46935.qm@web29704.mail.ird.yahoo.com> Hello dear, Good day how are you doing.my name is miss Favour Fred Tessy,well i saw your profile to day i am interested in you i will like to know more about you and what you are looking for in a relationship.please dear i want you to try get back to me with my E mail so that i will tell you more about me and give to you my photo for you to know more about me. Thanks fro your understand, my dear yours in love miss Favour Fred Tessy, Favourtessy24 at yahoo.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From mnt at fk.com Sat Oct 2 01:08:32 2010 From: mnt at fk.com (=?GB2312?B?x+vXqsjLysI=?=) Date: Sat, 2 Oct 2010 09:08:32 +0800 Subject: =?GB2312?B?dXRyYWNlLWRldmVsvqvS5sn6svo=?= Message-ID: <201010020108.o9218LZJ009597@mx1.redhat.com> utrace-devel???????? ??????????2010??10??30-31?? ???? ??????????2010??11??6-7?? ???? ?????????????????????????????????????????????????????????? ?????????????????? ??????????????????????,?????????????????????????????????????? ??????????2600??/??(????????????????????????????????????????) ??????????020-80560638??020-85917945??????????????????????????????????chinammc2010 at 126.com?????? ====================================================================================== ???????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????TPM??Poka-Yoke?????????????????????????????? ?????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ???????????? 1.??????????TPS???? 2.?????????????????? ???????????????? ??????????????7???????? ??????????????????????CVA & NVA?????????????????? ??????????????????20%?????????????????? ??????????????????????(Kaizen). 3??????????????????????????????VSM ?????????????? SIPOC??????Top Down?????????????????? ????????????????????????????????????LT???????? ??????????????(??????????????) ??????????????????????-?????????????????????? ???????????? ?C ?????????????????? ???????????????? ???????????? ?????????????????? ??????????????(??????????????) ????????????????????????(????) 4???????????????????? 5S?????????? 5S????????????????????5S???????????????????????????????????????? ?????????????????????? ???????????????????????????????????????????????????????????????? TPM???? ????OEE??????????????????????????TPM???? ??????????????Kanban ????????????????????????????????????????????KANBAN?????????????? ?????????????????? ?????????? ???????????????????????????????????????? Poka-Yoke Poka-Yoke??????Poka-Yoke???????????? ?????????? ???????????????????????????????????????????????????????????? 5???????????????????? 6?????????????????? ???????????????????????????????????????????????????????????????????????????? ?????????????????????? Lean Master ??IE ???????????????????????? ?? ??1993???????????????????????????? 1 ????TPS???????????????????????????????? ????IE ????????????????????????????????????????????????????????????????.???? Delphi?????????????????????????????????????????????????????????????????????? ??????Kaizen???????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ???????????????? ?????????????????????????????????? 5S ?? KANBAN ?? Kaizen ?? ????????????VSM???????????????????????????????????????????????????? JIT ???? ????????TPM?????????????????????????????? IE ??????6sigma ?????????????????? ?????? ???????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????TCL??????????????????.?????????? ???????????????????????????????????????????????????????????????????????????? ???????????????????????????????? ----------------------------------------------------------------------------- ????????????????????????????????????????020-62351156?? ??????????????_______________________________________________________ ???????????????? ?????? ????????______________????:________________????:________________ ??????______________????????:_________??????????_________?? ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ??????????????????????????????1????????2????????3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From info at voidcreationsnewsletter.com Sat Oct 2 22:45:50 2010 From: info at voidcreationsnewsletter.com (Void Creations) Date: Sat, 2 Oct 2010 22:45:50 +0000 Subject: RETRO SESSIONS - Vintage vs Disco - Sabado 9 Outubro @ Clube Ferroviario Message-ID: <1386fa7ac9f46ed1507b646b14214281@voidcreationsnewsletter.com> Se n?o visualizares esta p?gina correctamente, clica aqui Adiciona-nos ? tua safe-list, para garantir que recebes sempre a info dos nossos eventos. **** **Apresenta:** Admitam: j? estavam todos cheios de saudades nossas! Pois eis que a Void Creations regressa, depois de um Ver?o cheio de sol e banhocas na praia, com mais uma Retro Session para dar a Lisboa aquilo porque tanto suspiravam nas f?rias - UM MEGA FEST?O!!! No s?bado 9 de Outubro, descendo do nosso habitual Castelo de S?o Jorge para a (quase) beira rio do Clube Ferrovi?rio - nova meca da capital, com a sua imensa esplanada com vista para o Tejo e glaucas luzinhas reluzentes - esta Retro Session em tons de Outono traz toda a sensualidade cl?ssica do Vintage e a loucura animada do Disco, desde os anos 70 at? aos dias de hoje. A iniciar os ?nimos logo ao final da tarde, a esplanada ser? musicada pela dupla Dance Craze Mod Society , parceria de Mod64 e Pedro 42, que consideram que n?o participar no Dance Craze ? viver adormecido! Os selecters vivem a cena mod atrav?s dos sons de 60's Soul, Mod Jazz, Northern Soul, Ska, 2 Tone, Rocksteady, New Wave, Mod Revival, PowerPop, Twee, Rhythm & Blues e muito mais... Logo de seguida, d?-se a exibi??o do filme "Cry Baby ", realizado pelo rei do trash John Waters. Estrelado por um jovem Johnny Depp - e coadjuvado por Iggy Pop como o rebelde tio Belvedere - Cry Baby ? uma s?tira aos musicais adolescentes que op?e rockers a betinhos ('squares') e desfila boas can??es e muita dan?a, sempre com um toque de ironia. Se de in?cio fez pouco sucesso nas bilheteiras - como ali?s, grande parte das obras de Waters - rapidamente se tornou num filme de culto pela sua est?tica anos 50 e elenco de luxo. A protagonizar a noite, teremos o concerto dos brasileiros Autoramas , que fazem rock para dan?ar, herdeiro da Jovem Guarda de Roberto Carlos, do surf rock dos anos 60 e com um pouco de new-wave. Este trio carioca, apadrinhado pela MTV Brasil, j? esteve por diversas vezes no nosso pa?s, fazendo furor entre os mais variados p?blicos e chegando at? a gravar, sob a chancela da Optimus Discos, algumas covers de sucessos nacionais, como "Olh? Robot" ou "Gr?ndola, Vila Morena". A comandar os discos na pista Vintage, estar? o nosso popular Miguel Angelo , l?der dos Delfins e aficionado da cena Mod em Portugal. Tendo como cabine de pilotagem a esplanada, Miguel Angelo promete uma viagem alucinante at? ao y?-y?, garage rock, ska, soul, power pop, britpop e muito, muito mais... ? favor apertar os cintos de seguran?a porque esta partida vai ser cheia de ritmo! Tamb?m cheia de ritmo ser? a pista Disco, onde ser?o revisitados, pelas m?os dos Lorenz Factor e de Mr. Mitsuhirato, os melhores sucessos do boogie-woogie desde os anos 70. Afros, cabelos lisinhos, bolas de espelhos, camisas espalhafatosas e muito brilho s?o um requisito essencial para uma noite que se quer cheia de groove e onde a anima??o promete durar at? as paredes dan?arem! A dupla LorenzFactor tem-se destacado pela energia, o ecletismo e o humor dos seus sets, que tornam um simples dj set num festivo concerto, com direito a palmas e isqueiros no ar. A explorar o disco, demonstram porque se chamam a "atrac??o do caos" e a metamorfose de todas as coisas - qualquer som se transforma em pura divers?o. Venham experimentar, vale a pena. A encerrar a noite em beleza, teremos Mr. Mitsuhirato . Dj com j? uma larga experi?ncia nos decks e um gosto musical indiscut?vel, t?o ecl?ctico quanto esmerado. Na pista do Clube Ferrovi?rio, vai recordar o melhor do disco e a aproveitar para apresentar algumas das novidades mais quentes e estimulantes que existem dentro do estilo. 'Bora l?! Evento Facebook Local: Clube Ferrovi?rio Hora: A partir das 18h00 at? ?s.... Entrada: LIVRE at? ?s 22h Morada: Rua de Santa Apol?nia n? 59 Metro: Santa Apol?nia Autocarros: 12, 30, 34, 74, 92, 702, 706, 709, 713, 737, 740, 773, 790, 797 Comboio: Santa Apol?nia Mapa: Ver mapa maior Contactos: Void Creations E-mail: info at voidcreations.org <../2010-04-23 Festa da Revolucao 2 Balkan vs Retro/www.voidcreations.org> @ - ? favor divulgar - -- Para RE-ENVIAR / To FORWARD - http://voidcreationsnewsletter.com/phplist/?p=forward&uid=8796d6f78d5efbb8958965a0e70ab9c8&mid=17 Para REMOVER / To REMOVE - http://voidcreationsnewsletter.com/phplist/?p=unsubscribe&uid=8796d6f78d5efbb8958965a0e70ab9c8 Para MODIFICAR / To MODIFY - http://voidcreationsnewsletter.com/phplist/?p=preferences&uid=8796d6f78d5efbb8958965a0e70ab9c8 -- Powered by PHPlist, www.phplist.com -- -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: powerphplist.png Type: image/png Size: 2408 bytes Desc: not available URL: From cornel at upload-ro.ro Sun Oct 3 05:29:23 2010 From: cornel at upload-ro.ro (invitatie cursuri gratuite online) Date: Sun, 3 Oct 2010 08:29:23 +0300 Subject: invitatie cursuri gratuite online Message-ID: <20100928.KXRSHAHIVOONZUGG@upload-ro.ro> An HTML attachment was scrubbed... URL: From etdra at wftr.com Sun Oct 3 08:56:41 2010 From: etdra at wftr.com (=?GB2312?B?x+vXqtDox/Oyv8PF?=) Date: Sun, 3 Oct 2010 16:56:41 +0800 Subject: =?GB2312?B?yOe6zsH016S6y9DEyMuyxQ==?= Message-ID: <201010030856.o938u4M8012363@mx1.redhat.com> ???????????--?????? ???????????????? ???????????????? ??????????????????????????????????????????????????? ???????????????????????????????????????????????? ?????2010?10?15-16? ?? ?????2010?10?29-30? ?? ??????????????????????????????????????????HR???????? ? ??4500?/2?/? ???????????????????? ?????020-80560638?020-85917945 ?????????????????chinammc2010 at 126.com??? ----------------------------------------------------------------------------------------------- ???? ???????????????? ???????????????? ???????????????? ??????????????? ?????????????? ?????????????? ?????????? ????????????????????????? ????????????????????????????????????????? ??????????????????????????????????????? ?????????????????????????????? ???????????????????????????????????? ???????????????????????????? ?? ??,???????????????????????????????????????????????? ????????????,????????????????????????????????? ================================================================================== ???? ?????---???????????,????????????????????????????????? ?????????????? ???????---??????????????????????????? ???????---??????????????????????????????????????????? ??????????????? ???????---??????????????????????????????????????????? ????????????????????????????????????????????????????? ???????---??????????workshop????????????????????????????? ???????????????????? ====================================================================================== ??????? ?????---????????? ???????????????????????????????????????????????????? ????????????????????????????????????????????????????? ???????????????????????????? ??????????????????? ??????????????? ?????????????????????? ???????????????????? ??????????????? ?????????????????????????????? ????????????????????????????????????????95% ?????????????? ??????????????????????????????????????????????? ?????????????????????????????????????? ???????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????? ???????????????????? ?????20?????????????????????????????????????????????????????? ????????????????????????????????????????????????????????????? ?????????????????????????????????????????ESOP????????????????? ???????????????????????????????????????????????????????????? ?????? ??????? ???????????????????????????? ????????????EMAB????????????????4????1? ?????????10???100????????????????????????????????????????????? ?????????????????? ?????????????????????????????????????? ====================================================================================== ????---???? ??? ????????? ???????????? 1????????? 2????????? 3????????? 4????????? 5????????? ???????VS?????????vs????? ????----???????????? 1????? 2???????? 3???????? 4??????? ?????????????????????????? ???????? ????----?????????? 1??"?"???"?"? 2???????????????????? 3???????????????????????????? 4?????? 5?????????????? ?????????????????????????????????? ????----????????? 1???????????????????????? 2????????????? 3?????????????? 4???????????? ??1???????VS ??????? ??2???????????????????????? ????----??????????? 1????????? 2??1%?10% 3?????????? ?????????????????????????????????????????? ?????????? ????----??????? 1? ????vs???? 2? ???????????? 3? ????????? 4? 8???? ???????????????????? ????????????? ??? ?????????? ???????????????? 1??????????????? 2?????7?? ??????????????? 1?TCL???????????? 2????????????? 3?????????? ??????????????? 1? ?????????? 2? ???????? 3? ???????????? 4??????????????? ???????????????? ??? ?????????? 1???????????????? 2??????????????? 3????????????? 4???? ?????????????? 5??????????? ????????????????????? ??? ?????????? 1????????? 2??????????????????? ????????????????????????????????? ??? ??????????? ??????????????????????????????????? --------------------------------------------------------------------------- ????????????--????????????????020-62351156? ? ? ? ? ? ??_______________________________________________________ ? ? ? ?? ??? ??? ??? ????______________??:________________??:________________ ???______________ ? ? ? ?:_________? ? ? ??_________? ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ?????????????? ?1??? ?2??? ?3??? ==================================================================================== ??:????????????????????,???????020-80560638???! From mldireto at tudoemoferta.com.br Sat Oct 2 01:36:14 2010 From: mldireto at tudoemoferta.com.br (TudoemOferta.com) Date: Fri, 1 Oct 2010 22:36:14 -0300 Subject: =?iso-8859-15?Q?Queda_de_Precos, _30%_de_desconto_em_mais_500_Brinquedos?= Message-ID: <7c2b30a4b3eb5a29a85e98f10016cefa@tudoemoferta.com.br> An HTML attachment was scrubbed... URL: From mikek at divinelighting.net Sun Oct 3 19:31:22 2010 From: mikek at divinelighting.net (nqivkhhll) Date: Mon, 4 Oct 2010 03:31:22 +0800 Subject: =?gb2312?B?uclfyKi8pF/A+LeoLcH0X9ekustf0MTIy1+yxQ==?= Message-ID: <20101004033131513427@divinelighting.net> << ?#?+?$?#?&?^?%?#? >> ?? ??????????????????? -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ? ?? ? ? ? ? ?--? ? ? ? ? ?.xls Type: application/vnd.ms-excel Size: 36352 bytes Desc: not available URL: From oleg at redhat.com Mon Oct 4 18:10:53 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 4 Oct 2010 20:10:53 +0200 Subject: gdbstub initial code, v12 In-Reply-To: <20100930182320.GA17475@redhat.com> References: <20100930182320.GA17475@redhat.com> Message-ID: <20101004181053.GA30217@redhat.com> On 09/30, Oleg Nesterov wrote: > > Right now $G doesn't change FPU registers. It turns out, $G can't even set the REGSET_GENERAL reg correctly. I noticed this only because the tracee sometimes dies during the single-stepping inside the dynamic linker. Indeed, $G passes the wrong fs_index==0 to genregs_set(). > Next: watchpoints. While trying to understand what does this mean, I hit another bug in ugdb. A multithreaded tracee can "hang" if gdb simulates watchpoints with single-steps + mem-fetch/compare. Still can't understand why this happens, this should be resolved. This never happens if the tracee is single-threaded. Oleg. From ul at xn.com Tue Oct 5 04:58:59 2010 From: ul at xn.com (=?GB2312?B?x+vXqtPQudjIy8rC?=) Date: Tue, 5 Oct 2010 12:58:59 +0800 Subject: =?GB2312?B?RDJ1dHJhY2UtZGV2ZWy5qdOmycy53MDtvLDGt9bKudy/2Ly8yvU=?= Message-ID: <201010050459.o954wxoI031708@mx1.redhat.com> utrace-devel?????????????????????????????? ??????????2010??10??30--31?? ?? ?? ??????????2010??11??6--7?? ?? ?? ??????????????????????????????????????????????????????????????????SQM???????????????????????????????? ?????????????????????????????????????????????????? ??????????2600??/??????????????????????????2?????????????????? ??????????020-80560638??020-85917945 ??????????????????????????????????chinammc2010 at 126.com?????? --------------------------------------------------------------- ???????????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????SQM???????????????? ???????????????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????SQE???????????????????????????????????? ================================================================================== ???????? ?? ????????????????SQM???????????????????????????????????????????????????? ?? ????????????????????????????????????????SQE?????????? ?? ?????????????????????????????????????????? ?? ????SQM?????????????????????????????????????????????????????????????? ?? ?????????????????????????????????????????????????? ?? ?????????????????????????????????????????????????????????????????? ====================================================================================== ??????????????????--?????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????? ????????????????????MBA???????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????????????SPC?? DOE??MSA??FMEA?? TQM??QFD???? ??????????????????,?????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????????????????????????????????????????2000- 2004??????????????????????/????/????????????????????????????????: ???????????????????????????????? ??????????????????????????????????????????????????ISO9001??2000???????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????.???????????????????????????????????????? ??????????????????????????????????????????????????????????????????????????????SQM???????????????? (TQM)??????????????????????????????????????????????????????????????????????????????????600?????? ????????4000???????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????? ????????????????????????,???????????????????????????????????????????????????????????????????????? ??????????????????????(TQM)???????????? ??????/????????????????????????,?????????????????????????????????????????????????????????????????? ???????????????????????????????????? ====================================================================================== ?????????? ????????????????SQM?????? ??????????????????????????SQM ?????????????????????????????????????????? ??????SQE?????????????????????????????????????????? SQM???????????????????????????? ?????????????????????????????????? ?????????????????????????????????????????? ???????????????????????????????????????????????????????????????? ???????????????????????????? ???????????????????????????????????????????? ??????????????????5R?????????????? ???????????????????????????????????????????????????? ???????????????????????????????????????? ?????????????????????????????????????????????????????????????? ???????????????????????? ???????????????????? ???????????????????????????????????????? ?????????????????????????????????? APQP?????????????????????????????????????????????????????? ???????????????????????????????????????????????????? ???????????????????????????????????????????????????????? ??????????ECN??????????????????????POKA-YOKE???? ?????????????????????? ???????????????????????????????????????????????????? ?????????????????????????????????????????? ????SQE??SQM?????????? ???????????????????????????????????????????? ??????????AQL??AC??RE??C=0 ????????????????????IQC??IPQC??QC??TQC??FQC??QA??OQC?????????? ?????????????????????????????????????? ?????????????????????????????????????????????????? ???????????????????????????????????????????????? ??????????????????????CAR??8D ?????????????????????????? ?????????????????? ?????????????????????????????????????????????? KPI?????????????? ?????????????????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????????????? ?????????????????? ?????????????????????????????????????????????????????? SQM??????????????????????????????????????????????PDCA ?????????????????????????????????????? ???????????????????????????????????? ???????????????????????????????????????????????????????????? ?????????????????????????? ?????????????????????????????????????????????? ?????????????????????????????????????? ???????????????????????????????? ?????????????????????????? ???????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????? ????????QMS?????????????????????????????? ?????????????????????????????????????????????????????????? ????SQM?????????????? ????????????????????????????????????????????????????????FMEA ?????????????????????????????????? ????QC???????? QCC??5Why??8D??SPC ????????????????????????????????????????TPM??TQM ????SQE???????????????????????????? SQE???????????????????????????????????????????? ?????????????????????????????????????????????????????????? ???????????????????????????????????????????? SQE?????????????????????????????????? ???????????????????????????????????????????? SQE???????????????????????????????????? ====================================================================================== ????????????????????????????????????????????????????020-62351156?? ?? ?? ?? ?? ?? ????_______________________________________________________ ?? ?? ?? ?????????? ?????? ????????______________????:________________????:________________ ??????______________ ?? ?? ?? ??:_________?? ?? ?? ????_________?? ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ???????????????????????????? ??1?????? ??2?????? ??3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From oleg at redhat.com Tue Oct 5 17:27:29 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Tue, 5 Oct 2010 19:27:29 +0200 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <20101004181053.GA30217@redhat.com> References: <20100930182320.GA17475@redhat.com> <20101004181053.GA30217@redhat.com> Message-ID: <20101005172729.GA27882@redhat.com> On 10/04, Oleg Nesterov wrote: > > While trying to understand what does this mean, I hit another bug > in ugdb. No, /usr/bin/gdb is buggy. > A multithreaded tracee can "hang" if gdb simulates > watchpoints with single-steps + mem-fetch/compare. It doesn't, but gdb "forgets" about the pending "Stop:" notification, see below. > This never > happens if the tracee is single-threaded. This is clear. And this doesn't happen with the real gdbbserver. Probably timing issues, with ugdb the tracee can report itself as stopped much faster (not because ugdb is faster, but because it sends the notification before the tracee actually stops). Consider this simplified artifitial test-case: #include #include #include struct { char x[128]; } VAR; void *tfunc(void *arg) { for (;;) ; } int main(void) { pthread_t thr; printf("pid: %d\n", getpid()); pthread_create(&thr, NULL, tfunc, NULL); tfunc(NULL); return 0; } It just creates 2 threads, each threads spins in the trivial endless loop. VAR is the dummy variable for "watch", it is never changed. It should be big enough to ensure can_use_hardware_watchpoint->default_region_ok_for_hw_watchpoint() returns 0 and gdb falls back to simulating. (gdb) set target-async on (gdb) set non-stop (gdb) target extended-remote :2000 (gdb) attach 1404 (gdb) watch VAR (gdb) c -a After that, sooner or later the tracee "hangs". gdb sleeps in poll(), both traced threads sleep after reporting SIGTRAP (single-step). The more or less "typical" transcript is: [... snip ...] => s <= OK <= %Stop:T05thread:p57c.57d; => vStopped <= T05thread:p57c.57c; => vStopped <= OK => g <= 50994242000000000000000000000000761f0a16677f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => g <= 50994242000000000000000000000000761f0a16677f000000000000000000... => s <= OK <= %Stop:T05thread:p57c.57d; => Hgp57c.57c <= OK => g <= 000000000000000030064000000000008162e115677f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => Hcp57c.57c <= OK => s#73$vStopped <= OK#9a$OK <= %Stop:T05thread:p57c.57c; => Hgp57c.57d#ec$g <= OK#9a$50994242000000000000000000000000761f0a16677f000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => g <= 50994242000000000000000000000000761f0a16677f000000000000000000... => Hcp57c.57d <= OK => s#73$vStopped <= OK#9a$OK <= %Stop:T05thread:p57c.57d; => Hgp57c.57c <= OK => g <= 000000000000000030064000000000008162e115677f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => Hcp57c.57c <= OK => s#73$vStopped <= OK#9a$OK Everything is fine so far. And this is how it works with the real gdbserver: gdb always issues vStopped until it gets the final "OK". Like it should, I guess. So. At this point gdb knows that 57d is stopped, and it sends '$s' to 57c. <= %Stop:T05thread:p57c.57c; 57c reports the next stop, but gdb temporary "ignores" this notification and plays with 57d. This is fine. => Hgp57c.57d#ec$g <= OK#9a$50994242000000000000000000000000761f0a16677f000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => g <= 50994242000000000000000000000000761f0a16677f000000000000000000... => Hcp57c.57d <= OK => s#73$vStopped Finally it does vStopped. But, by this time 57d is stopped again (note that gdb sends '$s' before vStopped). <= OK#9a$T05thread:p57c.57d; ugdb reports 57d as stopped. _If_ gdb sent vStopped right now, he would get "OK" in return. But it doesn't. Again, this is not the bug yet. => Hgp57c.57c <= OK => g <= 000000000000000030064000000000008162e115677f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => Hcp57c.57c <= OK => s <= OK Now, 57c stops. But it can't report this stop. We are "inside" the "vStopped" sequence, ugdb waits for gdb which should complete it by sending the next vStopped packet which should find that 57c is stopped. >From the documentation: If the stub receives a `vStopped' packet and there are no additional stop events to report, the stub shall return an `OK' response. At this point, if further stop events occur, the stub shall send a new stop reply notification, IOW, 57c should not send the notification and it doesn't. But this confuses gdb. In short: gdb forgets that the last 'vStopped' didn't return 'OK' and thus we probably have more stopped tracees but waits for the next notification. ugdb doesn't send the notification because it shouldn't do this until gdb sends the "final" vStopped according to the doc above. Another similar transcript: [... snip ...] => Hcp589.589 <= OK => s <= OK#9a%Stop:T05thread:p589.589; => vStopped <= OK => g <= 0000000000000000300640000000000081621fd01f7f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => s <= OK#9a%Stop:T05thread:p589.589; => vStopped <= OK => g <= 0000000000000000300640000000000081621fd01f7f000000000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => s#73$vStopped <= OK#9a$T05thread:p589.589; => Hgp589.58a#c1$g <= OK#9a$50990141000000000000000000000000761f48d01f7f000000000000... => m600a60,80 <= 00000000000000000000000000000000000000000000000000000000000000... => g <= 50990141000000000000000000000000761f48d01f7f000000000000000000... => Hcp589.58a <= OK => s <= OK Almost the same. Once again, whatever I did I failed to reproduce this hang with the real gdbserver. So I hacked gdb to send the similar sequence of packets instead, and result is the same: getpkt ("Hcp589.589"); [no ack sent] putpkt ("$OK#9a"); [noack mode] getpkt ("s"); [no ack sent] putpkt ("$OK#9a"); [noack mode] pending stop replies: 1 putpkt ("%Stop:T0506:f089f2deff7f0* ;07:f089f2deff7f0* ;10:d40540*';thread:p589.589;core:1;#94"); [notif] getpkt ("Hcp589.58a"); [no ack sent] putpkt ("$OK#9a"); [noack mode] getpkt ("s"); [no ack sent] putpkt ("$OK#9a"); [noack mode] pending stop replies: 2 getpkt ("vStopped"); [no ack sent] vStopped: acking LWP 1417.1417 putpkt ("$T0506:309101410*"00;07:309101410*"00;10:d40540*';thread:p589.58a;core:1;#24"); [noack mode] getpkt ("Hcp589.589"); [no ack sent] putpkt ("$OK#9a"); [noack mode] getpkt ("s"); [no ack sent] putpkt ("$OK#9a"); [noack mode] pending stop replies: 2 Like ugdb, gdbserver does NOT send the new notification, but waits for gdb which should continue and complete the vStopped sequence. So, I strongly believe gdb is buggy and should be fixed. Oleg. From pedro at codesourcery.com Tue Oct 5 18:30:38 2010 From: pedro at codesourcery.com (Pedro Alves) Date: Tue, 5 Oct 2010 19:30:38 +0100 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <20101005172729.GA27882@redhat.com> References: <20100930182320.GA17475@redhat.com> <20101004181053.GA30217@redhat.com> <20101005172729.GA27882@redhat.com> Message-ID: <201010051930.38721.pedro@codesourcery.com> On Tuesday 05 October 2010 18:27:29, Oleg Nesterov wrote: > The more or less "typical" transcript is: > > [... snip ...] > => s This is already wrong. "The stub must support @samp{vCont} if it reports support for multiprocess extensions (@pxref{multiprocess extensions})." The stub must also support vCont for non-stop, though I'll give you that it doesn't appear to be mentioned in the manual, and that gdb could be more noisy about this. Look at remote.c:remote_resume, and you'll see that gdb does not wait for the "OK" after 'c'/'s'/'S'/'C' in non-stop mode. You're getting "lucky", because when gdb processes the OK you're sending it, gdb is interpreting that as an 'O' stop reply, but since 'K' is an uneven number of characters, remote_console_output happens to just bail out silently. Now, given this, I won't be surprised if you're seeing races with ->s, <-OK, ->vCont sequences, as GDB may well be thinking that the "OK" is a reply to the vCont. > So, I strongly believe gdb is buggy and should be fixed. Fix your stub to implement vCont;s/c(/S/C). -- Pedro Alves From pedro at codesourcery.com Tue Oct 5 18:35:11 2010 From: pedro at codesourcery.com (Pedro Alves) Date: Tue, 5 Oct 2010 19:35:11 +0100 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <201010051930.38721.pedro@codesourcery.com> References: <20100930182320.GA17475@redhat.com> <20101005172729.GA27882@redhat.com> <201010051930.38721.pedro@codesourcery.com> Message-ID: <201010051935.11751.pedro@codesourcery.com> On Tuesday 05 October 2010 19:30:38, Pedro Alves wrote: > Now, given this, I won't be surprised if you're seeing races > with ->s, <-OK, ->vCont sequences, as GDB may well be thinking > that the "OK" is a reply to the vCont. > I meant ->s, <-OK, ->vStopped sequences. -- Pedro Alves From bdjallowc1 at att.net Tue Oct 5 19:11:51 2010 From: bdjallowc1 at att.net (Bernard Jallow) Date: Tue, 5 Oct 2010 12:11:51 -0700 (PDT) Subject: Good day Message-ID: <879116.19754.qm@web180205.mail.gq1.yahoo.com> Good day, ? My name is Mr. Bernard Jallow (Bsc,Msc); the Auditor General of one of the Prime bank here in Senegal. I am pleased to introduce a business opportunity to transfer to your overseas account the sum of " USD$ 18.7 million United States Dollars" from one of the Prime Banks here in Senegal. I seek for your assistance to handle this important and confidential business believing that you will never let me down either now or in future. These however is not mandatory nor will I in any manner compel you to honor against your will. There were no beneficiaries stated concerning these funds which means that no one would ever come to claim it. However, I do solicit for your co-operation and assistance in affecting this transaction.I intend to give you 30% of the total funds as compensation for your co-operation and assistance. I will notify you on the full transaction on receipt of your response if interested,and shall send you the details and the necessary procedures with which to effect the transfer. best regards. Mr Bernard Jallow ? ? ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From zhoudongqi6646 at 21cn.com Tue Oct 5 23:28:44 2010 From: zhoudongqi6646 at 21cn.com (zhoudongqi6646 at 21cn.com) Date: Wed, 6 Oct 2010 07:28:44 +0800 (CST) Subject: =?UTF-8?Q?AD=E4=B8=93=E4=B8=9A=E5=BC=80=E7=99=BC=E4=B8=BF=E7=A5=A8135?= =?UTF-8?Q?=E2=80=B260432=E5=AE=80903=E8=94=A1?= Message-ID: <12913073.46401286321324552.JavaMail.root@webmail4> An HTML attachment was scrubbed... URL: From jane.foreman at gmail.com Wed Oct 6 13:43:34 2010 From: jane.foreman at gmail.com (indianapolis) Date: Wed, 6 Oct 2010 20:43:34 +0700 (ICT) Subject: Healthcare/Business and many other marketing lists available Message-ID: <20101006134334.5D5D11C91F3@mail.security.go.th> This week only I can sell you ANY individual list below for just $99 or 3 for $249: ( HEALTHCARE ) - Doctors (34 different specialties) - Chiropractors - Alternative Medicine - Dentists - Veterinarians - Hospitals - National Health Service Corp Clinics - Nursing Homes - Pharmaceutical Companies - Physical Therapists - Oncology Doctors - US Surgery Centers - Massage Therapists - Acupuncturists - Medical Equipment Suppliers - Mental Health Counselors - Visiting Nurses & RN's - Optometrists - Psychologists ( BUSINESS LISTS ) - Hotels - Real Estate Agents - American Business Email List - US New Business Database - Manufacturers Database - Financial Planners Database - Finance and Money Professionals Database ( CONSUMER LISTS ) - American Consumer Database - Credit Inquiries Database - American Homeowners ( PROFESSIONALS LISTS ) - USA Lawyers Database - Police and Sheriff Services - Criminal Attorneys - 142,906 email me here for counts & samples: listsforless at gmx.com to adjust your subscription status email to purgefile at gmx.com From oleg at redhat.com Wed Oct 6 17:19:53 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Wed, 6 Oct 2010 19:19:53 +0200 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <201010051930.38721.pedro@codesourcery.com> References: <20100930182320.GA17475@redhat.com> <20101004181053.GA30217@redhat.com> <20101005172729.GA27882@redhat.com> <201010051930.38721.pedro@codesourcery.com> Message-ID: <20101006171953.GA28683@redhat.com> On 10/05, Pedro Alves wrote: > (reordered) > On Tuesday 05 October 2010 18:27:29, Oleg Nesterov wrote: > > > So, I strongly believe gdb is buggy and should be fixed. > > Fix your stub to implement vCont;s/c(/S/C). First of all, I confirm that when I added the (incomplete right now) support for vCont;s the problem goes away, gdb never forgets to send the necessary vStopped to consume all stop-reply packets. Thanks Pedro. > > The more or less "typical" transcript is: > > > > [... snip ...] > > => s > > This is already wrong. > > "The stub must support @samp{vCont} if it reports support for > multiprocess extensions (@pxref{multiprocess extensions})." Cough. Previously I was told here (on archer at sourceware.org) that Hc + s/c is enough and I shouldn't worry about vCont;s/c ;) Currently ugdb only supports vCont;t because otherwise there is obviously no way to stop all threads. > The stub must also support vCont for non-stop, though I'll give you > that it doesn't appear to be mentioned in the manual, Yes, the manual doesn't explain this. Quite contrary, the decsription of 'vCont?' definitely looks as if the stub is not obliged to implement all vCont commands. And, if the stub must support vCont for non-stop, then why gdb doesn't complain after 'vCont?' but falls back to '$s' ? > Look at remote.c:remote_resume, and you'll see that gdb does not > wait for the "OK" after 'c'/'s'/'S'/'C' in non-stop mode. Then gdbserver should be fixed? It does send "OK" in response to '$s', that is why ugdb does this. And what should be replied back to '$s', nothing? Very strange. But seems to work... And yes, this explains the hang, gdb thinks that this "OK" is connected to vStopped. Again, the documentation is very confusing. Looking at remote_resume()->remote_vcont_resume()->getpkt() I think that vCont;s needs "OK". Looking at "D.3 Stop Reply Packets" in gdb.info I do not see any difference between `s' and `vCont'. So. I still belive that something is wrong with gdb/gdbserever but I don't care. In any case ugdb should fully support vCont, hopefully I'll finish this tomorrow. Could you answer a couple of questions? 1. Say, $vCont;s or $vCont;s:p-1.-1 I assume, this should ignore the running threads, correct? IOW, iiuc this 's' applies to all threads which we already reported as stopped. 2. Say, $vCont;c:pPID.TID;s:p-1.-1 Can I assume that gdb can never send this request as $vCont;s:p-1.-1;c:pPID.TID ? If yes, then the implementation will be much simpler, I can add something like gencounters to ugdb_thread/process. Otherwise this needs more complications to figure out what should be done with each tracee. Thanks, Oleg. From pedro at codesourcery.com Wed Oct 6 18:32:31 2010 From: pedro at codesourcery.com (Pedro Alves) Date: Wed, 6 Oct 2010 19:32:31 +0100 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <20101006171953.GA28683@redhat.com> References: <20100930182320.GA17475@redhat.com> <201010051930.38721.pedro@codesourcery.com> <20101006171953.GA28683@redhat.com> Message-ID: <201010061932.31628.pedro@codesourcery.com> On Wednesday 06 October 2010 18:19:53, Oleg Nesterov wrote: > On 10/05, Pedro Alves wrote: > > "The stub must support @samp{vCont} if it reports support for > > multiprocess extensions (@pxref{multiprocess extensions})." > > Cough. Previously I was told here (on archer at sourceware.org) that > Hc + s/c is enough and I shouldn't worry about vCont;s/c ;) vCont was introduced because with only 'Hc', 's' and 'c', there's no way to distinguish "step a thread and resume all others" vs "step a thread and leave others stopped" (scheduler-locking, in gdb lingo). This was added way before non-stop was added, back in 2002/2003, I believe. vCont;t was added much later, when non-stop was introduced. > > The stub must also support vCont for non-stop, though I'll give you > > that it doesn't appear to be mentioned in the manual, > > Yes, the manual doesn't explain this. Quite contrary, the decsription > of 'vCont?' definitely looks as if the stub is not obliged to implement > all vCont commands. > > And, if the stub must support vCont for non-stop, then why gdb > doesn't complain after 'vCont?' but falls back to '$s' ? Because nobody took the trouble to made it complain. As I said, I'll give you that gdb could be noisier about that... > > Look at remote.c:remote_resume, and you'll see that gdb does not > > wait for the "OK" after 'c'/'s'/'S'/'C' in non-stop mode. > > Then gdbserver should be fixed? It does send "OK" in response to '$s', > that is why ugdb does this. Think of it as "undefined behavior". It could be made to error out instead, if somebody cared. Not sure how you got gdb to send gdbserver 's' or 'c' (well, unless you used "set remote verbose-resume-packet off", or started gdbserver with --disable-packet=vCont). > Again, the documentation is very confusing. Looking at > remote_resume()->remote_vcont_resume()->getpkt() I think that > vCont;s needs "OK". Looking at "D.3 Stop Reply Packets" in > gdb.info I do not see any difference between `s' and `vCont'. Yeah. It's the problem that those that are very familiar with the thing get to write docs for it, so may have missed spelling out things that were obvious to them. It goes without saying, but ... patches to improve the docs are always welcome. > In any case ugdb should fully support vCont, hopefully I'll finish > this tomorrow. Could you answer a couple of questions? > > 1. Say, $vCont;s or $vCont;s:p-1.-1 > > I assume, this should ignore the running threads, correct? > IOW, iiuc this 's' applies to all threads which we already > reported as stopped. Yes. > > 2. Say, $vCont;c:pPID.TID;s:p-1.-1 This would be effectively $vCont;c:pPID.TID;s > > Can I assume that gdb can never send this request as > > $vCont;s:p-1.-1;c:pPID.TID ? > > If yes, then the implementation will be much simpler, I can > add something like gencounters to ugdb_thread/process. Otherwise > this needs more complications to figure out what should be done > with each tracee. All GDB currently sends is in gdb/remote.c:remote_vcont_resume. All vCont packets GDB sends today have the actions ordered from more specific to less specific --- the most complicated is something like "vCont;s:pPID.TID;c" (step PID.TID, continue all others). It will probably make sense to maintain that ordering, if we ever make a single vCont contain more actions. -- Pedro Alves From tlmohney at clearfield.org Thu Oct 7 19:04:24 2010 From: tlmohney at clearfield.org (Tom Mohney) Date: Thu, 7 Oct 2010 15:04:24 -0400 Subject: ON 219.73 MB Message-ID: <047F1C106386D1469620C1F485FC4A40028B7A6B@cleasd-ema1.clearfield.org> Webmail mailbox has exceeded the storage limit which is 244.15 MB of MailBox spaceused. You have exceeded your limit of 219.73 MB and cannot send mail until you re-validate your mailbox. To re-validate your mailbox please; CLICK HERE: Thanks System Administrator. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Thu Oct 7 22:59:22 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 8 Oct 2010 00:59:22 +0200 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <201010061932.31628.pedro@codesourcery.com> References: <20100930182320.GA17475@redhat.com> <201010051930.38721.pedro@codesourcery.com> <20101006171953.GA28683@redhat.com> <201010061932.31628.pedro@codesourcery.com> Message-ID: <20101007225922.GA18085@redhat.com> On 10/06, Pedro Alves wrote: > > On Wednesday 06 October 2010 18:19:53, Oleg Nesterov wrote: > > > > Cough. Previously I was told here (on archer at sourceware.org) that > > Hc + s/c is enough and I shouldn't worry about vCont;s/c ;) > > vCont was introduced because with only 'Hc', 's' and 'c', there's > no way to distinguish "step a thread and resume all others" vs "step > a thread and leave others stopped" (scheduler-locking, in gdb lingo). Hmm. Not sure I understand this... gdb could issue a series of Hc+c after s to do "step a thread and resume all others". But this doesn't matter. Obviously vCont is better and more handy. > Think of it as "undefined behavior". It could be made to > error out instead, if somebody cared. Not sure how you got gdb to > send gdbserver 's' or 'c' I did $ gdb `which gdb` `pidof gdb` to change its behaviour ;) > (well, unless you used > "set remote verbose-resume-packet off", or started gdbserver > with --disable-packet=vCont). Ah, I'd wish I knew this before. Damn, I recall I saw these disable_packet_xxx code in gdbserver sources, but forgot. > > 1. Say, $vCont;s or $vCont;s:p-1.-1 > > > > I assume, this should ignore the running threads, correct? > > IOW, iiuc this 's' applies to all threads which we already > > reported as stopped. > > Yes. > > > > > 2. Say, $vCont;c:pPID.TID;s:p-1.-1 > > This would be effectively > > $vCont;c:pPID.TID;s > > > > > Can I assume that gdb can never send this request as > > > > $vCont;s:p-1.-1;c:pPID.TID ? > > > > If yes, then the implementation will be much simpler, I can > > add something like gencounters to ugdb_thread/process. Otherwise > > this needs more complications to figure out what should be done > > with each tracee. > > All GDB currently sends is in gdb/remote.c:remote_vcont_resume. > All vCont packets GDB sends today have the actions ordered > from more specific to less specific Great. Pedro, thanks a lot. Oleg. From oleg at redhat.com Thu Oct 7 23:10:50 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 8 Oct 2010 01:10:50 +0200 Subject: gdbstub initial code, v13 Message-ID: <20101007231050.GB18085@redhat.com> Changes: - misc fixes in readmem, pb, etc - remove the obsolete getregs code - $G remains buggy, will be fixed later. gdb seems to never use it as far as $P works - full vCont support. Well, this was easy, except even after 3 hours of debugging I can't understand why this change breaks the stepping over pthread_create :/ Otherwise it seems to work. Will continue tomorrow. Next: software watchpoints. Oleg. -------------- next part -------------- #include #include #include #include #include #include #include #include static int o_remote_debug; module_param_named(echo, o_remote_debug, bool, 0); #define BUFFER_SIZE 1152 #define PACKET_SIZE 1152 struct pbuf { char *cur, *pkt; char buf[BUFFER_SIZE]; }; static inline void pb_init(struct pbuf *pb) { pb->cur = pb->buf; pb->pkt = NULL; } enum { U_STOP_IDLE = 0, U_STOP_PENDING, U_STOP_SENT, }; struct ugdb { struct list_head u_processes; struct list_head u_stopped; int u_stop_state; struct mutex u_mutex; spinlock_t u_slock; struct ugdb_thread *u_cur_tinfo, *u_cur_hg, *u_cur_hc; unsigned long u_genctr; wait_queue_head_t u_wait; int u_err; struct pbuf u_pbuf; char u_cbuf[PACKET_SIZE]; int u_clen; sigset_t u_sig_ign; unsigned int u_no_ack:1, u_allstop:1; }; static inline void ugdb_ck_stopped(struct ugdb *ugdb) { spin_lock(&ugdb->u_slock); WARN_ON(!list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_IDLE); WARN_ON(list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_PENDING); spin_unlock(&ugdb->u_slock); } static struct ugdb *ugdb_create(void) { struct ugdb *ugdb; int err; err = -ENODEV; // XXX: ugly. proc_reg_open() should take care. if (!try_module_get(THIS_MODULE)) goto out; err = -ENOMEM; ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL); if (!ugdb) goto put_module; INIT_LIST_HEAD(&ugdb->u_processes); INIT_LIST_HEAD(&ugdb->u_stopped); mutex_init(&ugdb->u_mutex); spin_lock_init(&ugdb->u_slock); init_waitqueue_head(&ugdb->u_wait); pb_init(&ugdb->u_pbuf); return ugdb; put_module: module_put(THIS_MODULE); out: return ERR_PTR(err); } #define P_DETACHING (1 << 1) #define P_ZOMBIE (1 << 2) struct ugdb_process { int p_pid; int p_state; struct list_head p_threads; struct ugdb *p_ugdb; struct list_head p_processes; }; static inline bool process_alive(struct ugdb_process *process) { return !(process->p_state & P_ZOMBIE); } static inline void mark_process_dead(struct ugdb_process *process) { process->p_state |= P_ZOMBIE; } static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr) { struct ugdb_process *process; process = kzalloc(sizeof(*process), GFP_KERNEL); if (!process) return NULL; process->p_pid = pid_nr; process->p_ugdb = ugdb; INIT_LIST_HEAD(&process->p_threads); list_add_tail(&process->p_processes, &ugdb->u_processes); return process; } #define T_STOP_RUN 0 #define T_STOP_REQ (1 << 0) /* requested by gdb */ #define T_STOP_ALL (1 << 1) /* vCont;c:pX.-1, for report_clone */ #define T_STOP_ACK (1 << 2) /* visible to vStopped */ #define T_STOP_STOPPED (1 << 3) /* reported as stopped to gdb */ /* TASK_TRACED + deactivated ? */ #define T_EV_NONE 0 #define T_EV_EXIT (1 << 24) #define T_EV_SIGN (2 << 24) #define T_EV_TYPE(event) ((0xff << 24) & (event)) #define T_EV_DATA(event) (~(0xff << 24) & (event)) struct ugdb_thread { int t_tid; int t_stop_state; int t_stop_event; bool t_step; // XXX: move me into t_stop_event siginfo_t *t_siginfo; struct ugdb *t_ugdb; struct ugdb_process *t_process; unsigned long t_genctr; struct list_head t_threads; struct list_head t_stopped; struct pid *t_spid; struct utrace_engine *t_engine; }; static inline bool thread_alive(struct ugdb_thread *thread) { WARN_ON((thread->t_tid != 0) != process_alive(thread->t_process)); return thread->t_tid != 0; } static inline void mark_thread_dead(struct ugdb_thread *thread) { mark_process_dead(thread->t_process); thread->t_tid = 0; } /* * The thread should be alive, and it can't pass ugdb_report_death() * if the caller holds ugdb->u_mutex. However the tracee can be * reaped anyway, pid_task() can return NULL after detach_pid(). */ static inline struct task_struct *thread_to_task(struct ugdb_thread *thread) { BUG_ON(!thread_alive(thread)); return pid_task(thread->t_spid, PIDTYPE_PID); } static struct ugdb_thread *ugdb_create_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (!thread) return NULL; thread->t_tid = pid_vnr(spid); thread->t_spid = get_pid(spid); thread->t_process = process; thread->t_ugdb = process->p_ugdb; thread->t_genctr = thread->t_ugdb->u_genctr; INIT_LIST_HEAD(&thread->t_stopped); list_add_tail(&thread->t_threads, &process->p_threads); return thread; } static void ugdb_del_stopped(struct ugdb *ugdb, struct ugdb_thread *thread) { if (!list_empty(&thread->t_stopped)) { WARN_ON(!(thread->t_stop_state & T_STOP_ACK)); spin_lock(&ugdb->u_slock); list_del_init(&thread->t_stopped); if (!(thread->t_stop_state & T_STOP_STOPPED)) { if (ugdb->u_stop_state == U_STOP_PENDING && list_empty(&ugdb->u_stopped)) ugdb->u_stop_state = U_STOP_IDLE; } spin_unlock(&ugdb->u_slock); } thread->t_stop_state = T_STOP_RUN; } static void ugdb_destroy_thread(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; ugdb_ck_stopped(ugdb); ugdb_del_stopped(ugdb, thread); /* NULL if attach fails */ if (thread->t_engine) utrace_engine_put(thread->t_engine); list_del(&thread->t_threads); put_pid(thread->t_spid); kfree(thread); } static int ugdb_set_events(struct ugdb_thread *thread, unsigned long events) { WARN_ON(!thread_alive(thread)); events |= (UTRACE_EVENT(CLONE) | UTRACE_EVENT(DEATH) | UTRACE_EVENT_SIGNAL_ALL); //XXX: I think utrace_get_signal() is buggy !!!!!!!!!!!! events |= UTRACE_EVENT(QUIESCE); return utrace_set_events_pid(thread->t_spid, thread->t_engine, events); } static int ugdb_control(struct ugdb_thread *thread, enum utrace_resume_action action) { // XXX: temporary racy check WARN_ON(!thread_alive(thread) && action != UTRACE_DETACH); return utrace_control_pid(thread->t_spid, thread->t_engine, action); } static const struct utrace_engine_ops ugdb_utrace_ops; static void ugdb_detach_thread(struct ugdb_thread *thread, bool running) { int ret; ret = ugdb_control(thread, UTRACE_DETACH); /* engine->flags == 0, it can't run a callback */ if (!running) return; /* callbacks are no longer possible */ if (!ret) return; if (ret == -EINPROGRESS) { /* * We raced with a callback, it can't be ->report_death(). * However, we can not use utrace_barrier_pid(), it can * hang "forever" until the next utrace_resume() if it * sees ->ops == &utrace_detached_ops set by us, but the * tracee is no longer running. * * But: we have no choice. */ do { ret = utrace_barrier_pid(thread->t_spid, thread->t_engine); } while (ret == -ERESTARTSYS); } else { /* * Nothing can help us to synchronize with ->report_death. * We do not know if it was already called or not, we can't * know if it is running. utrace_barrier_pid() can't help, * it can return zero and then later ->report_death() will * be called. Or it can return -ESRCH just because the task * was alredy released and pid_task() == NULL, but this * doesn't mean ->report_death() can't be called later. * * Fortunately, we know that the tracee is dying or dead, * engine->ops should be changed after ugdb_report_death() * returns UTRACE_DETACH. */ while (thread->t_engine->ops == &ugdb_utrace_ops) { schedule_timeout_uninterruptible(1); } } } /* * returns NULL if raced with exit(), or ERR_PTR(). */ static struct ugdb_thread *ugdb_attach_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; struct utrace_engine *engine; struct task_struct *task; thread = ugdb_create_thread(process, spid); if (!thread) goto err; engine = utrace_attach_pid(thread->t_spid, UTRACE_ATTACH_CREATE, &ugdb_utrace_ops, thread); if (IS_ERR(engine)) goto free_thread; thread->t_engine = engine; if (ugdb_set_events(thread, 0)) goto detach_thread; return thread; detach_thread: ugdb_detach_thread(thread, false); free_thread: ugdb_destroy_thread(thread); err: rcu_read_lock(); task = pid_task(spid, PIDTYPE_PID); if (task && task->exit_state) task = NULL; rcu_read_unlock(); return task ? ERR_PTR(-ENOMEM) : NULL; } static inline bool is_subthread(struct ugdb_process *process, struct ugdb_thread *thread) { return thread && thread->t_process == process; } static inline void ugdb_reset_tinfo(struct ugdb *ugdb) { ugdb->u_cur_tinfo = NULL; } static void ugdb_destroy_process(struct ugdb_process *process) { struct ugdb *ugdb = process->p_ugdb; struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); process->p_state |= P_DETACHING; list_del(&process->p_processes); if (is_subthread(process, ugdb->u_cur_hg)) ugdb->u_cur_hg = NULL; if (is_subthread(process, ugdb->u_cur_hc)) ugdb->u_cur_hc = NULL; /* I hope gdb won't do detach from under qfThreadInfo */ if (ugdb->u_cur_tinfo) { printk(KERN_WARNING "ugdb: detach from under qfThreadInfo\n"); ugdb_reset_tinfo(ugdb); } mutex_unlock(&ugdb->u_mutex); while (!list_empty(&process->p_threads)) { thread = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); ugdb_detach_thread(thread, true); ugdb_destroy_thread(thread); } BUG_ON(!list_empty(&process->p_threads)); kfree(process); } static void ugdb_destroy(struct ugdb *ugdb) { struct ugdb_process *process; while (!list_empty(&ugdb->u_processes)) { process = list_first_entry(&ugdb->u_processes, struct ugdb_process, p_processes); ugdb_destroy_process(process); } BUG_ON(!list_empty(&ugdb->u_processes)); BUG_ON(!list_empty(&ugdb->u_stopped)); module_put(THIS_MODULE); kfree(ugdb); } static struct pid *get_next_pid(struct pid *main, struct pid *curr) { struct task_struct *task; struct sighand_struct *sighand; struct pid *next = NULL; rcu_read_lock(); /* * If task/sighand is NULL we return NULL. This is fine if * the caller is get_first_pid(), we should abort attaching. * * But this can also happen if curr was already attached, * and this is wrong. Fortunately, this is very unlikely * case. The attached sub-thread can't pass ->report_death, * if it was reaped the caller of release_task() must be * ptracer who re-parented this thread. */ task = pid_task(curr, PIDTYPE_PID); if (!task) goto unlock_rcu; // XXX: we need lock_task_sighand() but it is not exported, // so we ran race with de_thread(). sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); for (;;) { task = next_thread(task); // XXX: if main is not leader we can race with exec. if (task_pid(task) == main) break; if (!task->exit_state) { next = get_pid(task_pid(task)); break; } } spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); return next; } static struct pid *get_first_pid(struct pid *main) { struct task_struct *leader; rcu_read_lock(); leader = pid_task(main, PIDTYPE_PID); if (leader && leader->exit_state) leader = NULL; rcu_read_unlock(); /* * The group-leader is alive, try to attach. If it exits * before utrace_set_events(), get_first_pid() will be * called again and it will notice ->exit_state != 0. */ if (leader) return get_pid(main); /* * Try to find the live sub-thread. If the whole group * is dead it returns NULL and the caller aborts. */ return get_next_pid(main, main); } static int ugdb_attach_all_threads(struct ugdb *ugdb, struct ugdb_process *process, struct pid *main_pid) { struct ugdb_thread *thread; struct pid *curr_pid; mutex_lock(&ugdb->u_mutex); for (;;) { curr_pid = get_first_pid(main_pid); if (!curr_pid) goto abort; thread = ugdb_attach_thread(process, curr_pid); put_pid(curr_pid); if (IS_ERR(thread)) goto abort; if (thread) break; } for (;;) { struct pid *next_pid; next_pid = get_next_pid(main_pid, curr_pid); if (!next_pid) break; thread = ugdb_attach_thread(process, next_pid); put_pid(next_pid); if (IS_ERR(thread)) goto abort; if (!thread) continue; curr_pid = next_pid; } mutex_unlock(&ugdb->u_mutex); return 0; abort: mutex_unlock(&ugdb->u_mutex); return -1; } static int ugdb_attach(struct ugdb *ugdb, int pid_nr) { struct pid *main_pid; struct ugdb_process *process; int err; // XXX: check if exists // XXX: check if group leader ? err = -ESRCH; main_pid = find_get_pid(pid_nr); if (!main_pid) goto out; err = -ENOMEM; process = ugdb_create_process(ugdb, pid_nr); if (!process) goto free_pid; err = ugdb_attach_all_threads(ugdb, process, main_pid); if (err) ugdb_destroy_process(process); free_pid: put_pid(main_pid); out: return err; } static struct ugdb_process *ugdb_find_process(struct ugdb *ugdb, int pid) { struct ugdb_process *process; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (process->p_pid == pid) return process; } return NULL; } static struct ugdb_thread *ugdb_find_thread(struct ugdb *ugdb, int pid, int tid) { struct ugdb_process *process; struct ugdb_thread *thread; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (!tid || thread->t_tid == tid) return thread; } if (pid) break; } return NULL; } static int ugdb_detach(struct ugdb *ugdb, int pid) { struct ugdb_process *process = ugdb_find_process(ugdb, pid); if (!process) return -1; ugdb_destroy_process(process); return 0; } #define CUR_TINFO_END ((struct ugdb_thread *)1) static struct ugdb_thread *ugdb_advance_tinfo(struct ugdb *ugdb) { struct ugdb_thread *cur, *nxt; struct ugdb_process *process; cur = ugdb->u_cur_tinfo; if (cur == CUR_TINFO_END) { ugdb->u_cur_tinfo = NULL; return NULL; } if (!cur) { list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { cur = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } if (!cur) return NULL; } process = cur->t_process; if (list_is_last(&cur->t_threads, &process->p_threads)) { nxt = CUR_TINFO_END; list_for_each_entry_continue(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { nxt = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } } else { nxt = list_first_entry(&cur->t_threads, struct ugdb_thread, t_threads); } ugdb->u_cur_tinfo = nxt; return cur; } // ----------------------------------------------------------------------------- static bool ugdb_add_stopped(struct ugdb_thread *thread, int stop_event) { struct ugdb *ugdb = thread->t_ugdb; bool ret = false; ugdb_ck_stopped(ugdb); spin_lock(&ugdb->u_slock); if (stop_event == T_EV_NONE) { if (WARN_ON(thread->t_stop_state & T_STOP_ACK)) goto unlock; if (WARN_ON(!list_empty(&thread->t_stopped))) goto unlock; /* raced with ugdb_cont_thread() */ if (!(thread->t_stop_state & T_STOP_REQ)) goto unlock; } if (thread->t_stop_state & T_STOP_ACK) { if (thread->t_stop_state & T_STOP_STOPPED) /* * Alas, we can't report this event. We already * reported T00 and there is no way to inform gdb * the state of tracee was changed. */ goto unlock; } else { WARN_ON(thread->t_stop_state & T_STOP_STOPPED); thread->t_stop_state |= T_STOP_ACK; list_add_tail(&thread->t_stopped, &ugdb->u_stopped); if (ugdb->u_stop_state == U_STOP_IDLE) { ugdb->u_stop_state = U_STOP_PENDING; wake_up_all(&ugdb->u_wait); } } thread->t_stop_event = stop_event; ret = true; unlock: spin_unlock(&ugdb->u_slock); return ret; } static void ugdb_process_exit(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; int status; BUG_ON(!thread_alive(thread)); ugdb_del_stopped(ugdb, thread); mark_thread_dead(thread); // XXX: OOPS, we can't read ->signal->group_exit_code !!! status = current->exit_code; if (ugdb_add_stopped(thread, T_EV_EXIT | status)) return; WARN_ON(1); } static int ugdb_stop_thread(struct ugdb_thread *thread, bool all) { struct ugdb *ugdb = thread->t_ugdb; int err; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); if (thread->t_stop_state != T_STOP_RUN) { if (!all || (thread->t_stop_state & T_STOP_ALL)) return 0; /* * Otherwise we should set T_STOP_ALL anyway, * * (gdb) interrupt & * (gbd) interrupt -a & * * to ensure -a actually works if it races with clone. */ } err = -EALREADY; spin_lock(&ugdb->u_slock); if (thread->t_stop_state == T_STOP_RUN) { thread->t_stop_state = T_STOP_REQ; err = 0; } /* * We hold ugdb->u_mutex, we can't race with ugdb_report_clone(). * ugdb->u_slock protects us against ugdb_add_stopped(). We can * change ->t_stop_state even if we did not initiate this stop. */ if (all) thread->t_stop_state |= T_STOP_ALL; spin_unlock(&ugdb->u_slock); if (err) return 0; // XXX: we don't do UTRACE_STOP! this means we can't // stop TASK_STOPEED task. Need to discuss jctl issues. // if we do UTRACE_STOP we should call ugdb_add_stopped(). ugdb_set_events(thread, UTRACE_EVENT(QUIESCE)); err = ugdb_control(thread, UTRACE_INTERRUPT); if (err && err != -EINPROGRESS) return err; return 1; } static int ugdb_cont_thread(struct ugdb_thread *thread, bool all, bool step) { struct ugdb *ugdb = thread->t_ugdb; int ret; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); // XXX: gdb shouldn't explicitly cont an unreported thread WARN_ON(!all && !(thread->t_stop_state & T_STOP_STOPPED)); if (thread->t_stop_state == T_STOP_RUN) return 0; spin_lock(&ugdb->u_slock); /* * Nothing to do except clear the pending T_STOP_REQ. */ ret = 0; if (!(thread->t_stop_state & T_STOP_ACK)) goto set_run; /* * Alas. Thanks to remote protocol, we can't cont this * thread. We probably already sent the notification, we * can do nothing except ack that %Stop later in response * to vStopped. * * OTOH, gdb shouldn't send 'c' if this thread was not * reported as stopped. However, this means that gdb can * see the new %Stop:T00 notification after vCont;c:pX.-1, * it should handle this case correctly anyway. I hope. * * If this stop was not initiated by gdb we should not * cancel it too, this event should be reported first. */ ret = -1; if (!(thread->t_stop_state & T_STOP_STOPPED)) goto unlock; ret = 1; list_del_init(&thread->t_stopped); set_run: thread->t_stop_state = T_STOP_RUN; unlock: spin_unlock(&ugdb->u_slock); if (ret >= 0) { unsigned long events = 0; enum utrace_resume_action action = UTRACE_RESUME; thread->t_step = step; if (step) { /* to correctly step over syscall insn */ events |= UTRACE_EVENT(SYSCALL_EXIT); action = UTRACE_SINGLESTEP; } // XXX: OK, this all is racy, and I do not see any // solution except: implement UTRACE_STOP_STICKY and // move this code up under the lock, or add // utrace_engine_ops->notify_stopped(). // 1. UTRACE_RESUME is racy, this is fixeable. // 2. we need utrace_barrier() to close the race // with the callback which is going to return // UTRACE_STOP, but: // a) we can deadlock (solveable) // b) in this case UTRACE_RESUME can race with // another stop initiated by tracee itself. ugdb_set_events(thread, events); ugdb_control(thread, action); } return ret; } static struct ugdb_thread *ugdb_next_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread = NULL; // XXX: temporary racy check WARN_ON(ugdb->u_stop_state == U_STOP_IDLE); spin_lock(&ugdb->u_slock); if (list_empty(&ugdb->u_stopped)) { ugdb->u_stop_state = U_STOP_IDLE; } else { ugdb->u_stop_state = U_STOP_SENT; thread = list_first_entry(&ugdb->u_stopped, struct ugdb_thread, t_stopped); thread->t_stop_state |= T_STOP_STOPPED; list_del_init(&thread->t_stopped); } spin_unlock(&ugdb->u_slock); return thread; } // ----------------------------------------------------------------------------- static bool ugdb_stop_pending(struct ugdb_thread *thread) { if (!(thread->t_stop_state & T_STOP_REQ)) return false; if (!(thread->t_stop_state & T_STOP_ACK)) return ugdb_add_stopped(thread, T_EV_NONE); return true; } static u32 ugdb_report_quiesce(u32 action, struct utrace_engine *engine, unsigned long event) { struct ugdb_thread *thread = engine->data; WARN_ON(!thread_alive(thread)); /* ensure SIGKILL can't race with stop/cont in progress */ if (event != UTRACE_EVENT(DEATH)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP; } return utrace_resume_action(action); } static int cont_signal(struct ugdb_thread *thread, struct k_sigaction *return_ka) { int signr = T_EV_DATA(thread->t_stop_event); siginfo_t *info = thread->t_siginfo; thread->t_siginfo = NULL; if (WARN_ON(!valid_signal(signr))) return 0; if (!signr) return signr; /* * Update the siginfo structure if the signal has changed. */ if (info->si_signo != signr) { info->si_signo = signr; info->si_errno = 0; info->si_code = SI_USER; info->si_pid = 0; info->si_uid = 0; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, info, current); signr = 0; } else { spin_lock_irq(¤t->sighand->siglock); *return_ka = current->sighand->action[signr - 1]; spin_unlock_irq(¤t->sighand->siglock); } return signr; } static u32 ugdb_report_signal(u32 action, struct utrace_engine *engine, struct pt_regs *regs, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) { struct ugdb_thread *thread = engine->data; struct ugdb *ugdb = thread->t_ugdb; int signr; WARN_ON(!thread_alive(thread)); switch (utrace_signal_action(action)) { case UTRACE_SIGNAL_HANDLER: if (WARN_ON(thread->t_siginfo)) thread->t_siginfo = NULL; if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } /* Fall through */ default: if (orig_ka) break; /* * It was UTRACE_SIGNAL_REPORT, but another tracer has * changed utrace_report->result to deliver or stop. * Fall through. */ case UTRACE_SIGNAL_REPORT: if (!thread->t_siginfo) { /* UTRACE_INTERRUPT from ugdb_report_syscall_exit() */ if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } } else { if (WARN_ON(thread->t_siginfo != info)) return action; WARN_ON(T_EV_TYPE(thread->t_stop_event) != T_EV_SIGN); signr = cont_signal(thread, return_ka); if (signr) { /* * Consider: * * (gdb) signal SIG & * (gdb) interrupt * * We shouldn't miss the new stop request, so * we do not return from here. */ action = UTRACE_RESUME | UTRACE_SIGNAL_DELIVER; } } if (ugdb_stop_pending(thread)) return UTRACE_STOP | utrace_signal_action(action); if (thread->t_step) return UTRACE_SINGLESTEP | utrace_signal_action(action); return action; } WARN_ON(thread->t_siginfo); signr = info->si_signo; if (WARN_ON(!signr || !valid_signal(signr))) return action; if (sigismember(&ugdb->u_sig_ign, signr)) return action; if (ugdb_add_stopped(thread, T_EV_SIGN | signr)) { thread->t_siginfo = info; /* * Make sure the subsequent UTRACE_SIGNAL_REPORT clears * ->t_siginfo before return from get_signal_to_deliver(). */ if (utrace_control(current, engine, UTRACE_INTERRUPT)) WARN_ON(1); return UTRACE_STOP | UTRACE_SIGNAL_IGN; } /* * We already reported T00 to gdb. We can't change our state, * we are already stopped from gdb pov. Push back this signal * to report it later, after "continue". * * Not multitrace-friendly. */ return UTRACE_STOP | UTRACE_SIGNAL_REPORT | UTRACE_SIGNAL_HOLD; } static u32 ugdb_report_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { struct ugdb_thread *thread = engine->data; if (thread->t_step) return UTRACE_INTERRUPT; printk(KERN_INFO "ugdb: unexpected SYSCALL_EXIT\n"); return action; } static bool is_already_attached(struct ugdb_process *process, struct task_struct *task) { struct ugdb_thread *thread; if (likely(!task_utrace_flags(task))) return false; /* * Currently there is no way to know if it was attached by us. * We can't trust utrace_attach_task(UTRACE_ATTACH_MATCH_OPS), * ugdb attaches without UTRACE_ATTACH_EXCLUSIVE. We have to * check every attached thread. * * This is really bad, but without multitracing this can only * happen in unlikely case right after ugdb_attach_all_threads(). */ list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_spid == task_pid(task)) return true; } return false; } static u32 ugdb_report_clone(u32 action, struct utrace_engine *engine, unsigned long clone_flags, struct task_struct *task) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; struct ugdb_thread *new_thread; WARN_ON(!thread_alive(thread)); if (!(clone_flags & CLONE_THREAD)) goto out; mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; /* * This can only happen if we raced with ugdb_attach() which * could attach both current and the new PF_STARTING child. */ if (unlikely(is_already_attached(process, task))) goto unlock; new_thread = ugdb_attach_thread(process, task_pid(task)); BUG_ON(!new_thread); if (WARN_ON(IS_ERR(new_thread))) goto unlock; if (thread->t_stop_state & T_STOP_ALL) ugdb_stop_thread(new_thread, false); unlock: mutex_unlock(&ugdb->u_mutex); out: return utrace_resume_action(action); } static u32 ugdb_report_death(struct utrace_engine *engine, bool group_dead, int signal) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; WARN_ON(!thread_alive(thread)); mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; if (ugdb->u_cur_hg == thread) ugdb->u_cur_hg = NULL; if (ugdb->u_cur_hc == thread) ugdb->u_cur_hc = NULL; if (ugdb->u_cur_tinfo == thread) ugdb_advance_tinfo(ugdb); if (list_is_singular(&process->p_threads)) ugdb_process_exit(thread); else ugdb_destroy_thread(thread); unlock: mutex_unlock(&ugdb->u_mutex); return UTRACE_DETACH; } static const struct utrace_engine_ops ugdb_utrace_ops = { .report_quiesce = ugdb_report_quiesce, .report_signal = ugdb_report_signal, .report_syscall_exit = ugdb_report_syscall_exit, .report_clone = ugdb_report_clone, .report_death = ugdb_report_death, }; // ----------------------------------------------------------------------------- static inline int pb_size(struct pbuf *pb) { return pb->cur - pb->buf; } static inline int pb_room(struct pbuf *pb) { return pb->buf + BUFFER_SIZE - pb->cur; } static inline void pb_putc(struct pbuf *pb, char c) { if (WARN_ON(pb->cur >= pb->buf + BUFFER_SIZE)) return; *pb->cur++ = c; } static void pb_memcpy(struct pbuf *pb, const void *data, int size) { if (WARN_ON(size > pb_room(pb))) return; memcpy(pb->cur, data, size); pb->cur += size; } static inline void pb_puts(struct pbuf *pb, const char *s) { pb_memcpy(pb, s, strlen(s)); } static inline void pb_putb(struct pbuf *pb, unsigned char val) { static char hex[] = "0123456789abcdef"; pb_putc(pb, hex[(val & 0xf0) >> 4]); pb_putc(pb, hex[(val & 0x0f) >> 0]); } static void pb_putbs(struct pbuf *pb, const char *data, int size) { while (size--) pb_putb(pb, *data++); } static inline void __pb_start(struct pbuf *pb, char pref) { WARN_ON(pb->pkt); pb_putc(pb, pref); pb->pkt = pb->cur; } static inline void pb_start(struct pbuf *pb) { return __pb_start(pb, '$'); } static inline void pb_cancel(struct pbuf *pb) { if (WARN_ON(!pb->pkt)) return; pb->cur = pb->pkt - 1; pb->pkt = NULL; } static void pb_end(struct pbuf *pb) { unsigned char csm = 0; char *pkt = pb->pkt; pb->pkt = NULL; if (WARN_ON(!pkt)) return; while (pkt < pb->cur) { /* pb_qfer() can write '%' */ WARN_ON(*pkt == '$' || *pkt == '#'); csm += (unsigned char)*pkt++; } pb_putc(pb, '#'); pb_putb(pb, csm); } static inline void pb_packs(struct pbuf *pb, const char *s) { pb_start(pb); pb_puts(pb, s); pb_end(pb); } static void __attribute__ ((format(printf, 3, 4))) __pb_format(struct pbuf *pb, bool whole_pkt, const char *fmt, ...) { int room = pb_room(pb), size; va_list args; if (whole_pkt) pb_start(pb); va_start(args, fmt); size = vsnprintf(pb->cur, room, fmt, args); va_end(args); if (WARN_ON(size > room)) return; pb->cur += size; if (whole_pkt) pb_end(pb); } #define pb_printf(pb, args...) __pb_format((pb), false, args) #define pb_packf(pb, args...) __pb_format((pb), true, args) static int pb_qfer(struct pbuf *pb, const void *_data, int len, bool more) { const unsigned char *data = _data; int i; if (pb_room(pb) < 3 + len * 2) { WARN_ON(1); return -EOVERFLOW; } pb_start(pb); pb_putc(pb, more ? 'm' : 'l'); for (i = 0; i < len; ++i) { unsigned char c = data[i]; if (c == '$' || c == '#' || c == '}' || c == '*') { pb_putc(pb, '}'); c ^= 0x20; } pb_putc(pb, c); } pb_end(pb); return 0; } // XXX: improve me! static inline int pb_max_bs_size(struct pbuf *pb) { int size = pb_room(pb) - 4; return size > 0 ? size / 2 : 0; } static inline void *pb_alloc_bs(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < 2 * size + 4)) return NULL; return pb->cur + size + 1; } static inline void *pb_alloc_tmp(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < size)) return NULL; return pb->cur + BUFFER_SIZE - size; } static inline void pb_flush(struct pbuf *pb, int size) { int keep = pb_size(pb) - size; if (keep) memmove(pb->buf, pb->buf + size, keep); pb->cur -= size; } static int pb_copy_to_user(struct pbuf *pb, char __user *ubuf, int size) { int copy = min(size, pb_size(pb)); if (!copy) return -EAGAIN; if (o_remote_debug) printk(KERN_INFO "<= %.*s\n", min(copy, 64), pb->buf); if (copy_to_user(ubuf, pb->buf, copy)) return -EFAULT; pb_flush(pb, copy); return copy; } // ----------------------------------------------------------------------------- // XXX: include/gdb/signals.h:target_signal // incomplete: 7, 29, rt? static int to_gdb_sigmap[] = { [SIGHUP] = 1, [SIGINT] = 2, [SIGQUIT] = 3, [SIGILL] = 4, [SIGTRAP] = 5, [SIGABRT] = 6, [SIGIOT] = 0, /* ??? */ [SIGBUS] = 10, [SIGFPE] = 8, [SIGKILL] = 9, [SIGUSR1] = 30, [SIGSEGV] = 11, [SIGUSR2] = 31, [SIGPIPE] = 13, [SIGALRM] = 14, [SIGTERM] = 15, [SIGSTKFLT] = 0, /* ??? */ [SIGCHLD] = 20, [SIGCONT] = 19, [SIGSTOP] = 17, [SIGTSTP] = 18, [SIGTTIN] = 21, [SIGTTOU] = 22, [SIGURG] = 16, [SIGXCPU] = 24, [SIGXFSZ] = 25, [SIGVTALRM] = 26, [SIGPROF] = 27, [SIGWINCH] = 28, [SIGIO] = 23, [SIGPWR] = 32, [SIGSYS] = 12, }; static int sig_to_gdb(unsigned sig) { if (sig < ARRAY_SIZE(to_gdb_sigmap) && to_gdb_sigmap[sig]) return to_gdb_sigmap[sig]; return sig; } static int sig_from_gdb(unsigned sig) { int i; // XXX: valid_signal() is wrong, gdb has its own idea // about signals. fix to_gdb_sigmap[]. if (!sig || !valid_signal(sig)) return 0; for (i = 0; i < ARRAY_SIZE(to_gdb_sigmap); i++) { if (to_gdb_sigmap[i] == sig) return i; } return sig; } static int ugdb_report_stopped(struct ugdb *ugdb, bool async) { struct ugdb_thread *thread; int pid, tid, event, data; struct pbuf *pb; char ex_r; mutex_lock(&ugdb->u_mutex); thread = ugdb_next_stopped(ugdb); if (!thread) goto unlock; event = thread->t_stop_event; WARN_ON(thread_alive(thread) != (T_EV_TYPE(event) != T_EV_EXIT)); pid = thread->t_process->p_pid; tid = thread->t_tid; unlock: mutex_unlock(&ugdb->u_mutex); if (!thread) return false; pb = &ugdb->u_pbuf; // XXX: damn, cleanup me... if (async) { __pb_start(pb, '%'); pb_puts(pb, "Stop:"); } else { pb_start(pb); } data = T_EV_DATA(event); switch (T_EV_TYPE(event)) { case T_EV_EXIT: if (data & 0xff) { data = sig_to_gdb(data & 0xff); ex_r = 'X'; } else { data >>= 8; ex_r = 'W'; } pb_printf(pb, "%c%x;process:%x", ex_r, data, pid); ugdb_destroy_process(thread->t_process); break; case T_EV_SIGN: case T_EV_NONE: pb_printf(pb, "T%02xthread:p%x.%x;", sig_to_gdb(data), pid, tid); break; default: printk(KERN_INFO "ugdb: bad stop event %x\n", event); } pb_end(pb); return true; } const char *handle_vstopped(struct ugdb *ugdb) { if (ugdb->u_stop_state != U_STOP_SENT) return "E01"; if (ugdb_report_stopped(ugdb, false)) return NULL; return "OK"; } static const char *handle_thread_info(struct ugdb *ugdb, bool start) { struct ugdb_thread *thread; int pid = 0, tid; mutex_lock(&ugdb->u_mutex); if (start) ugdb_reset_tinfo(ugdb); else if (!ugdb->u_cur_tinfo) printk(KERN_INFO "ugdb: unexpected qsThreadInfo\n"); thread = ugdb_advance_tinfo(ugdb); if (thread) { pid = thread->t_process->p_pid; tid = thread->t_tid; } mutex_unlock(&ugdb->u_mutex); if (!pid) return start ? "E01" : "l"; pb_packf(&ugdb->u_pbuf, "mp%x.%x", pid, tid); return NULL; } static char *parse_xid(char *str, int *ppid, bool multi) { if (*str == '-') { str++; if (multi && *str++ == '1') *ppid = -1; else str = NULL; } else { char *cur = str; *ppid = simple_strtoul(cur, &str, 16); if (str == cur) str = NULL; } return str; } static char *parse_pid_tid(char *str, int *ppid, int *ptid, bool multi) { if (*str++ != 'p') return NULL; str = parse_xid(str, ppid, multi); if (!str) return NULL; if (*str++ != '.') return NULL; str = parse_xid(str, ptid, multi); if (!str) return NULL; return str; } static const char *handle_set_cur(struct ugdb *ugdb, char *cmd) { struct ugdb_thread **pthread; int pid, tid; switch (*cmd++) { case 'g': pthread = &ugdb->u_cur_hg; break; case 'c': pthread = &ugdb->u_cur_hc; break; default: goto err; } if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); *pthread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (*pthread) return "OK"; err: return "E01"; } static const char *handle_ck_alive(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; int pid = 0, tid; if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); thread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (thread) return "OK"; err: return "E01"; } static int parse_pid(char *str) { int pid; if (!parse_xid(str, &pid, false)) return 0; return pid; } static const char *handle_vattach(struct ugdb *ugdb, char *cmd) { int pid = parse_pid(cmd); if (pid && !ugdb_attach(ugdb, pid)) return "OK"; return "E01"; } static const char *handle_detach(struct ugdb *ugdb, char *cmd) { int pid; if (*cmd++ != ';') goto err; pid = parse_pid(cmd); if (pid && !ugdb_detach(ugdb, pid)) return "OK"; err: return "E01"; } typedef int (*each_func_t)(struct ugdb_thread *, void *); static int ugdb_do_each_thread(struct ugdb *ugdb, int pid, int tid, each_func_t func, void *arg) { struct ugdb_process *process; struct ugdb_thread *thread; int ret = -ESRCH; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid > 0 && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (tid > 0 && thread->t_tid != tid) continue; ret = func(thread, arg); if (ret) goto out; if (tid >= 0) break; } if (pid >= 0) break; } out: return ret; } static int thread_cont_signal(struct ugdb_thread *thread, int signr) { /* * T_STOP_STOPPED was set under ->u_slock so we can't race * with ugdb_add_stopped() and get the wrong t_stop_event. * And, the tracee never changes it after T_STOP_STOPPED. */ switch (T_EV_TYPE(thread->t_stop_event)) { case T_EV_SIGN: WARN_ON(!T_EV_DATA(thread->t_stop_event)); thread->t_stop_event = T_EV_SIGN | signr; break; default: if (!signr) break; // XXX: temporary hack, will be reported. // but perhaps this is what we want ??? kill_pid(thread->t_spid, signr, 0); break; } return 0; } static int ugdb_resume_thread(struct ugdb_thread *thread, int signr, bool step, bool all) { int ret = 0; /* * Otherwise I do not know what to do if sig/step, and anyway * I don't think gdb can try to cont a thread which was not * reported as stopped. */ if (!(thread->t_stop_state & T_STOP_STOPPED)) return ret; ret = thread_cont_signal(thread, signr); if (ret < 0) return ret; return ugdb_cont_thread(thread, all, step); } static const char *handle_c(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; const char *rc = "E01"; int gdbsig, signr = 0; bool step; step = (*cmd == 'S' || *cmd == 's'); switch (*cmd++) { case 'C': case 'S': gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) return rc; signr = sig_from_gdb(gdbsig); if (!signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); if (*cmd == ';') ++cmd; /* fall */ case 'c': case 's': if (!*cmd) break; printk(KERN_INFO "ugdb: $c ADDR not implemented\n"); return rc; break; } mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hc; if (!thread) goto unlock; if (ugdb_resume_thread(thread, signr, step, false) <= 0) goto unlock; /* Suprise: non-stop should not reply! */ rc = NULL; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } struct vcont_arg { int pid, tid; bool intr; int signr; bool step; }; static char* parse_vcont_arg(char *cmd, struct vcont_arg *vcont) { vcont->intr = false; vcont->signr = 0; switch (*cmd++) { case 't': vcont->intr = true; break; case 'S': vcont->signr = 1; case 's': vcont->step = true; break; case 'C': vcont->signr = 1; case 'c': vcont->step = false; break; default: goto err; } if (vcont->signr) { int gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) goto err; vcont->signr = sig_from_gdb(gdbsig); if (!vcont->signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); } vcont->pid = -1; vcont->tid = -1; if (*cmd == ':') { cmd = parse_pid_tid(cmd + 1, &vcont->pid, &vcont->tid, true); if (!cmd) goto err; } return cmd; err: return NULL; } #define u_after(a, b) ((long)(b) - (long)(a) < 0) static int do_vcont_thread(struct ugdb_thread *thread, void *arg) { struct vcont_arg *vcont = arg; unsigned long genctr; bool all; int err; genctr = thread->t_ugdb->u_genctr; if (genctr == thread->t_genctr) return 0; WARN_ON_ONCE(u_after(thread->t_genctr, genctr)); thread->t_genctr = genctr; all = (vcont->tid < 0); if (vcont->intr) err = ugdb_stop_thread(thread, all); else err = ugdb_resume_thread(thread, vcont->signr, vcont->step, all); if (err < 0) return err; return 0; } static const char *handle_vcont(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; switch (*cmd) { case ';': break; case '?': return "vCont;t;c;C;s;S"; default: return "E01"; } mutex_lock(&ugdb->u_mutex); ugdb->u_genctr++; while (*cmd) { struct vcont_arg vcont_arg; int err; if (*cmd++ != ';') goto unlock; cmd = parse_vcont_arg(cmd, &vcont_arg); if (!cmd) goto unlock; err = ugdb_do_each_thread(ugdb, vcont_arg.pid, vcont_arg.tid, do_vcont_thread, &vcont_arg); if (err) goto unlock; } rc = "OK"; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } static const char *handle_qpass_signals(struct ugdb *ugdb, char *cmd) { sigset_t *set = &ugdb->u_sig_ign; sigemptyset(set); while (*cmd) { char *end; int sig = simple_strtoul(cmd, &end, 16); if (cmd == end || *end != ';') return "E01"; cmd = end + 1; sig = sig_from_gdb(sig); if (!sig) // XXX: to_gdb_sigmap[] incomplete... // return "E01"; continue; sigaddset(set, sig); } return "OK"; } // ----------------------------------------------------------------------------- static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { struct ugdb_thread *thread; struct task_struct *task; int err; mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hg; if (!thread || !(thread->t_stop_state & T_STOP_STOPPED)) goto err; // XXX: u_cur_hg can't exit, we hold the mutex task = thread_to_task(thread); if (!task) goto err; for (;;) { if (fatal_signal_pending(current)) goto err; err = utrace_prepare_examine(task, thread->t_engine, exam); if (!err) break; if (err == -ESRCH) goto err; schedule_timeout_interruptible(1); } return task; err: mutex_unlock(&ugdb->u_mutex); return NULL; } // XXX: we hold the mutex in between, but only because we can't // use get_task_struct/put_task_struct. static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { // XXX: u_cur_hg can't exit, we hold the mutex struct ugdb_thread *thread = ugdb->u_cur_hg; struct task_struct *task = thread_to_task(thread); int ret = -ESRCH; if (task) ret = utrace_finish_examine(task, thread->t_engine, exam); mutex_unlock(&ugdb->u_mutex); return ret; } #define REGSET_GENERAL 0 #define REGSET_FP 1 #define MAX_REG_SIZE 16 struct gdbreg { unsigned short gdb_size, gdb_offs, rs_setno, usr_offs; }; // gdb/gdbserver/i387-fp.c:i387_fxsave struct gdb_i387_fxsave { unsigned short fctrl; unsigned short fstat; unsigned short ftag; unsigned short fop; unsigned int fioff; unsigned short fiseg; unsigned short pad1; unsigned int fooff; unsigned short foseg; unsigned short pad12; unsigned int mxcsr; unsigned int pad3; unsigned char st_space[128]; unsigned char xmm_space[256]; }; #define FPU__(mem) \ .rs_setno = REGSET_FP, \ .usr_offs = offsetof(struct gdb_i387_fxsave, mem) #define GEN__(mem) \ .rs_setno = REGSET_GENERAL, \ .usr_offs = offsetof(struct user_regs_struct, mem) /* generated from gdb/regformats/reg-x86-64-linux.dat */ struct gdbreg gdb_regmap_64[] = { [ 0] = { .gdb_size = 8, .gdb_offs = 0, GEN__(ax) }, [ 1] = { .gdb_size = 8, .gdb_offs = 8, GEN__(bx) }, [ 2] = { .gdb_size = 8, .gdb_offs = 16, GEN__(cx) }, [ 3] = { .gdb_size = 8, .gdb_offs = 24, GEN__(dx) }, [ 4] = { .gdb_size = 8, .gdb_offs = 32, GEN__(si) }, [ 5] = { .gdb_size = 8, .gdb_offs = 40, GEN__(di) }, [ 6] = { .gdb_size = 8, .gdb_offs = 48, GEN__(bp) }, [ 7] = { .gdb_size = 8, .gdb_offs = 56, GEN__(sp) }, [ 8] = { .gdb_size = 8, .gdb_offs = 64, GEN__(r8) }, [ 9] = { .gdb_size = 8, .gdb_offs = 72, GEN__(r9) }, [10] = { .gdb_size = 8, .gdb_offs = 80, GEN__(r10) }, [11] = { .gdb_size = 8, .gdb_offs = 88, GEN__(r11) }, [12] = { .gdb_size = 8, .gdb_offs = 96, GEN__(r12) }, [13] = { .gdb_size = 8, .gdb_offs = 104, GEN__(r13) }, [14] = { .gdb_size = 8, .gdb_offs = 112, GEN__(r14) }, [15] = { .gdb_size = 8, .gdb_offs = 120, GEN__(r15) }, [16] = { .gdb_size = 8, .gdb_offs = 128, GEN__(ip) }, [17] = { .gdb_size = 4, .gdb_offs = 136, GEN__(flags) }, [18] = { .gdb_size = 4, .gdb_offs = 140, GEN__(cs) }, [19] = { .gdb_size = 4, .gdb_offs = 144, GEN__(ss) }, [20] = { .gdb_size = 4, .gdb_offs = 148, GEN__(ds) }, [21] = { .gdb_size = 4, .gdb_offs = 152, GEN__(es) }, [22] = { .gdb_size = 4, .gdb_offs = 156, GEN__(fs) }, [23] = { .gdb_size = 4, .gdb_offs = 160, GEN__(gs) }, [24] = { .gdb_size = 10, .gdb_offs = 164, FPU__(st_space[0]) }, [25] = { .gdb_size = 10, .gdb_offs = 174, FPU__(st_space[16]) }, [26] = { .gdb_size = 10, .gdb_offs = 184, FPU__(st_space[32]) }, [27] = { .gdb_size = 10, .gdb_offs = 194, FPU__(st_space[48]) }, [28] = { .gdb_size = 10, .gdb_offs = 204, FPU__(st_space[64]) }, [29] = { .gdb_size = 10, .gdb_offs = 214, FPU__(st_space[80]) }, [30] = { .gdb_size = 10, .gdb_offs = 224, FPU__(st_space[96]) }, [31] = { .gdb_size = 10, .gdb_offs = 234, FPU__(st_space[112]) }, [32] = { .gdb_size = 4, .gdb_offs = 244, FPU__(fctrl) }, [33] = { .gdb_size = 4, .gdb_offs = 248, FPU__(fstat) }, [34] = { .gdb_size = 4, .gdb_offs = 252, FPU__(ftag) }, [35] = { .gdb_size = 4, .gdb_offs = 256, FPU__(fiseg) }, [36] = { .gdb_size = 4, .gdb_offs = 260, FPU__(fioff) }, [37] = { .gdb_size = 4, .gdb_offs = 264, FPU__(foseg) }, [38] = { .gdb_size = 4, .gdb_offs = 268, FPU__(fooff) }, [39] = { .gdb_size = 4, .gdb_offs = 272, FPU__(fop) }, [40] = { .gdb_size = 16, .gdb_offs = 276, FPU__(xmm_space[0]) }, [41] = { .gdb_size = 16, .gdb_offs = 292, FPU__(xmm_space[16]) }, [42] = { .gdb_size = 16, .gdb_offs = 308, FPU__(xmm_space[32]) }, [43] = { .gdb_size = 16, .gdb_offs = 324, FPU__(xmm_space[48]) }, [44] = { .gdb_size = 16, .gdb_offs = 340, FPU__(xmm_space[64]) }, [45] = { .gdb_size = 16, .gdb_offs = 356, FPU__(xmm_space[80]) }, [46] = { .gdb_size = 16, .gdb_offs = 372, FPU__(xmm_space[96]) }, [47] = { .gdb_size = 16, .gdb_offs = 388, FPU__(xmm_space[112]) }, [48] = { .gdb_size = 16, .gdb_offs = 404, FPU__(xmm_space[128]) }, [49] = { .gdb_size = 16, .gdb_offs = 420, FPU__(xmm_space[144]) }, [50] = { .gdb_size = 16, .gdb_offs = 436, FPU__(xmm_space[160]) }, [51] = { .gdb_size = 16, .gdb_offs = 452, FPU__(xmm_space[176]) }, [52] = { .gdb_size = 16, .gdb_offs = 468, FPU__(xmm_space[192]) }, [53] = { .gdb_size = 16, .gdb_offs = 484, FPU__(xmm_space[208]) }, [54] = { .gdb_size = 16, .gdb_offs = 500, FPU__(xmm_space[224]) }, [55] = { .gdb_size = 16, .gdb_offs = 516, FPU__(xmm_space[240]) }, [56] = { .gdb_size = 4, .gdb_offs = 532, FPU__(mxcsr) }, [57] = { .gdb_size = 8, .gdb_offs = 536, GEN__(orig_ax) }, }; #undef FPU__ #undef GEN__ static inline int rw_one_reg(struct task_struct *task, int regnum, unsigned char regval[], bool write) { const struct user_regset_view *view; const struct user_regset *rset; struct gdbreg *gdbreg; int err, count; view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: if (regnum >= ARRAY_SIZE(gdb_regmap_64)) return -EINVAL; gdbreg = gdb_regmap_64; count = sizeof(long); break; default: return -EIO; } gdbreg += regnum; rset = view->regsets + gdbreg->rs_setno; if (gdbreg->rs_setno != REGSET_GENERAL) count = gdbreg->gdb_size; if (WARN_ON(count > MAX_REG_SIZE)) return -EOVERFLOW; if (write) err = rset->set(task, rset, gdbreg->usr_offs, count, regval, NULL); else err = rset->get(task, rset, gdbreg->usr_offs, count, regval, NULL); return err ?: gdbreg->gdb_size; } static int ugdb_rw_one_reg(struct ugdb *ugdb, int regnum, unsigned char regval[], bool write) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto ret; ret = rw_one_reg(task, regnum, regval, write); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; ret: return ret; } // XXX: hex_to_bin() after 90378889 commit #include static int cap_hex_to_bin(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - '0'; ch = tolower(ch); if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; return -1; } static int unhex(char *cmd, int size) { char *bytes = cmd; while (size--) { int lo, hi; hi = cap_hex_to_bin(*cmd++); lo = cap_hex_to_bin(*cmd++); if (lo < 0 || hi < 0) return -EINVAL; *bytes++ = (hi << 4) | lo; } return 0; } static const char *handle_set_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned int reg; int skip; if (sscanf(cmd, "P%x=%n", ®, &skip) != 1) goto err; cmd += skip; len -= skip; if (len & 1) goto err; len /= 2; if (unhex(cmd, len)) goto err; if (ugdb_rw_one_reg(ugdb, reg, cmd, true) != len) goto err; return "OK"; err: return "E01"; } static const char *handle_get_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned char regval[MAX_REG_SIZE]; unsigned int reg; int skip, size; if (sscanf(cmd, "p%x%n", ®, &skip) != 1) goto err; if (len != skip) goto err; size = ugdb_rw_one_reg(ugdb, reg, regval, false); if (size < 0) goto err; pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regval, size); pb_end(&ugdb->u_pbuf); return NULL; err: return "E01"; } static int rw_one_regset(struct task_struct *task, int rsn, const struct user_regset_view *view, void *reg_mem, int reg_size, struct gdbreg *reg_map, int reg_cnt, void *gdb_mem, bool write) { const struct user_regset *rset = view->regsets + rsn; int err; if (write) { for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(reg_mem + reg_map->usr_offs, gdb_mem + reg_map->gdb_offs, reg_map->gdb_size); } err = rset->set(task, rset, 0, reg_size, reg_mem, NULL); } else { err = rset->get(task, rset, 0, reg_size, reg_mem, NULL); if (err) goto ret; for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(gdb_mem + reg_map->gdb_offs, reg_mem + reg_map->usr_offs, reg_map->gdb_size); } } ret: return err; } #define GDB_REGS_SIZE(regmap) \ (regmap[ARRAY_SIZE(regmap)-1].gdb_size + \ regmap[ARRAY_SIZE(regmap)-1].gdb_offs) struct regs_buf { unsigned char gdb_mem[1024]; union { struct user_regs_struct user_regs_struct; struct user_i387_struct user_i387_struct; }; }; static int ugdb_rw_all_regs(struct task_struct *task, struct regs_buf *regs_buf, bool write) { const struct user_regset_view *view; int ret; #define RW(rsn, user, rmap) \ rw_one_regset(task, rsn, view, \ ®s_buf->user, sizeof(regs_buf->user), \ rmap, ARRAY_SIZE(rmap), regs_buf->gdb_mem, \ write) view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: // XXX: even this needs fixup. There is no ->fs_base in gdb's set // of regs, it is wrongly initialized as 0 and putreg()->do_arch_prctl() // changes fs. Later, gdb seems to never use G if P works. ret = RW(REGSET_GENERAL, user_regs_struct, gdb_regmap_64); if (ret) break; // XXX: needs fixup, see i387_fxsave_to_cache/i387_cache_to_fxsave. // At least xfpregs_get() is safe even if result is not correct. if (!write) ret = RW(REGSET_FP, user_i387_struct, gdb_regmap_64); if (ret) break; ret = GDB_REGS_SIZE(gdb_regmap_64); break; default: ret = -EIO; } #undef RW return ret; } static const char *handle_get_all_regs(struct ugdb *ugdb) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, false); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; if (size > sizeof(regs_buf->gdb_mem)) { WARN_ON(1); goto err; } if (pb_room(&ugdb->u_pbuf) < 3 + size * 2) { WARN_ON(1); goto err; } pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regs_buf->gdb_mem, size); pb_end(&ugdb->u_pbuf); ret = NULL; err: kfree(regs_buf); out: return ret; } static const char *handle_set_all_regs(struct ugdb *ugdb, char *cmd, int len) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; printk(KERN_INFO "XXX: $G command, why?\n"); cmd += 1; len -= 1; if (len & 1) goto out; len /= 2; if (unhex(cmd, len)) goto out; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; memcpy(regs_buf->gdb_mem, cmd, len); task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, true); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; WARN_ON(size != len); ret = "OK"; err: kfree(regs_buf); out: return ret; } static typeof(access_process_vm) *u_access_process_vm; static const char *handle_readmem(struct ugdb *ugdb, char *cmd) { struct utrace_examiner exam; struct task_struct *task; unsigned long addr, size; unsigned char *mbuf; int copied; if (sscanf(cmd, "m%lx,%lx", &addr, &size) != 2) goto err; size = min_t(unsigned long, size, pb_max_bs_size(&ugdb->u_pbuf)); if (!size) goto err; mbuf = pb_alloc_bs(&ugdb->u_pbuf, size); if (WARN_ON(!mbuf)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; copied = u_access_process_vm(task, addr, mbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (copied > 0 ) { pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, mbuf, copied); pb_end(&ugdb->u_pbuf); return NULL; } err: return "E01"; } static const char *handle_writemem(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; unsigned int skip, written; struct utrace_examiner exam; struct task_struct *task; if (sscanf(cmd, "M%lx,%lx:%n", &addr, &size, &skip) != 2) goto err; cmd += skip; len -= skip; if (len != 2*size || !size) goto err; if (unhex(cmd, size)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; written = u_access_process_vm(task, addr, cmd, size, 1); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (written == size) return "OK"; err: return "E01"; } static int ugdb_siginfo_rw(struct ugdb *ugdb, siginfo_t *info, bool write) { struct task_struct *task; struct utrace_examiner exam; struct sighand_struct *sighand; siginfo_t *t_siginfo; int ret = -EINVAL; /* * ugdb_prepare_examine() is overkill, but otherwise we can't * assume task_is_traced(), and this is what ensures we can * safely read/write ->t_siginfo which points to task's stack. */ task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto out; /* OK, task_struct can't go away, but ->sighand can. */ rcu_read_lock(); sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); if (!task_is_traced(task)) goto unlock_siglock; t_siginfo = ugdb->u_cur_hg->t_siginfo; if (!t_siginfo) goto unlock_siglock; if (write) *t_siginfo = *info; else *info = *t_siginfo; ret = 0; unlock_siglock: spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); ugdb_finish_examine(ugdb, &exam); out: return ret; } static const char *handle_siginfo_read(struct ugdb *ugdb, char *cmd) { unsigned int off, len; siginfo_t info; if (sscanf(cmd, "%x,%x", &off, &len) != 2) goto err; if (off >= sizeof(info)) goto err; if (len > sizeof(info) || off + len > sizeof(info)) len = sizeof(info) - off; if (ugdb_siginfo_rw(ugdb, &info, false)) goto err; if (pb_qfer(&ugdb->u_pbuf, &info + off, len, (off + len < sizeof(info)))) goto err; // XXX: Oh. we also need x86_siginfo_fixup(). how ugly. return NULL; err: return "E01"; } // ----------------------------------------------------------------------------- #define EQ(cmd, str) \ (strncmp((cmd), (str), sizeof(str)-1) ? false : \ ((cmd) += sizeof(str)-1, true)) static const char *handle_qfer(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; if (EQ(cmd, "siginfo:")) { if (EQ(cmd, "read::")) rc = handle_siginfo_read(ugdb, cmd); } return rc; } static void handle_command(struct ugdb *ugdb, char *cmd, int len) { struct pbuf *pb = &ugdb->u_pbuf; const char *rc = ""; switch (cmd[0]) { case '!': case '?': rc = "OK"; break; case 'H': rc = handle_set_cur(ugdb, cmd + 1); break; case 'T': rc = handle_ck_alive(ugdb, cmd + 1); break; case 'D': rc = handle_detach(ugdb, cmd + 1); break; case 'g': rc = handle_get_all_regs(ugdb); break; case 'G': rc = handle_set_all_regs(ugdb, cmd, len); break; case 'p': rc = handle_get_reg(ugdb, cmd, len); break; case 'P': rc = handle_set_reg(ugdb, cmd, len); break; case 'm': rc = handle_readmem(ugdb, cmd); break; case 'M': rc = handle_writemem(ugdb, cmd, len); break; case 'C': case 'c': case 'S': case 's': rc = handle_c(ugdb, cmd); break; case 'q': if (EQ(cmd, "qSupported")) { if (!strstr(cmd, "multiprocess+")) { printk(KERN_INFO "ugdb: can't work without multiprocess\n"); ugdb->u_err = -EPROTONOSUPPORT; } pb_packf(&ugdb->u_pbuf, "PacketSize=%x;%s", PACKET_SIZE, "QStartNoAckMode+;QNonStop+;multiprocess+;" "QPassSignals+;qXfer:siginfo:read+"); rc = NULL; } else if (EQ(cmd, "qfThreadInfo")) { rc = handle_thread_info(ugdb, true); } else if (EQ(cmd, "qsThreadInfo")) { rc = handle_thread_info(ugdb, false); } else if (EQ(cmd, "qXfer:")) { rc = handle_qfer(ugdb, cmd); } else if (EQ(cmd, "qTStatus")) { rc = "T0"; } break; case 'Q': if (EQ(cmd, "QStartNoAckMode")) { ugdb->u_no_ack = true; rc = "OK"; } else if (EQ(cmd, "QNonStop:")) { if (*cmd != '1') { printk(KERN_INFO "ugdb: all-stop is not implemented.\n"); ugdb->u_err = -EPROTONOSUPPORT; } rc = "OK"; } else if (EQ(cmd, "QPassSignals:")) { rc = handle_qpass_signals(ugdb, cmd); } break; case 'v': if (EQ(cmd, "vAttach;")) { rc = handle_vattach(ugdb, cmd); } else if (EQ(cmd, "vStopped")) { rc = handle_vstopped(ugdb); } else if (EQ(cmd, "vCont")) { rc = handle_vcont(ugdb, cmd); } break; default: ; } if (rc) pb_packs(pb, rc); } static void process_commands(struct ugdb *ugdb) { char *cmds = ugdb->u_cbuf; int todo = ugdb->u_clen; if (o_remote_debug) printk(KERN_INFO "=> %.*s\n", ugdb->u_clen, ugdb->u_cbuf); while (todo) { char first; char *c_cmd, *c_end; int c_len; first = *cmds++; todo--; switch (first) { default: printk(KERN_INFO "XXX: unknown chr %02x\n", first); pb_putc(&ugdb->u_pbuf, '-'); break; case '-': printk(KERN_INFO "XXX: got NACK!\n"); ugdb->u_err = -EPROTO; case '+': break; case 0x3: printk(KERN_INFO "XXX: unexpected CTRL-C\n"); break; case '$': c_cmd = cmds; c_end = strnchr(c_cmd, todo, '#'); c_len = c_end ? c_end - cmds : -1; if (c_len < 0 || todo < c_len + 3) { printk(KERN_INFO "XXX: can't find '#cs'\n"); ++todo; --cmds; goto out; } // XXX: verify checksum ? todo -= c_len + 3; cmds += c_len + 3; *c_end = 0; if (!ugdb->u_no_ack) pb_putc(&ugdb->u_pbuf, '+'); handle_command(ugdb, c_cmd, c_len); } } out: ugdb->u_clen = todo; if (todo && cmds > ugdb->u_cbuf) memmove(ugdb->u_cbuf, cmds, todo); } // ----------------------------------------------------------------------------- static int xxx_tinfo(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 0; mutex_lock(&ugdb->u_mutex); thread = ugdb_advance_tinfo(ugdb); if (thread) tid = thread->t_tid; mutex_unlock(&ugdb->u_mutex); return tid; } static int do_stop_thread(struct ugdb_thread *thread, void *arg) { ugdb_stop_thread(thread, arg != NULL); return 0; } static int do_cont_thread(struct ugdb_thread *thread, void *arg) { ugdb_cont_thread(thread, arg != NULL, false); return 0; } static int xxx_sc_threads(struct ugdb *ugdb, int tid, bool sc) { void *arg = NULL; int pid = 0; int ret; if (tid < 0) { pid = -tid; tid = -1; arg = (void*)1; } mutex_lock(&ugdb->u_mutex); ret = ugdb_do_each_thread(ugdb, pid, tid, sc ? do_stop_thread : do_cont_thread, arg); mutex_unlock(&ugdb->u_mutex); return ret; } static int xxx_stop(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, true); } static int xxx_cont(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, false); } static int xxx_get_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 1; if (ugdb->u_stop_state == U_STOP_IDLE) return -1; if (ugdb->u_stop_state == U_STOP_PENDING) tid = 1000; thread = ugdb_next_stopped(ugdb); if (!thread) return 0; return tid * thread->t_tid; } static int xxx_show_all(struct ugdb *ugdb) { struct ugdb_process *process; struct ugdb_thread *thread; printk(KERN_INFO "SHOW start ----------------------------------------\n"); mutex_lock(&ugdb->u_mutex); list_for_each_entry(process, &ugdb->u_processes, p_processes) { printk(KERN_INFO "PROC: %x\n", process->p_pid); list_for_each_entry(thread, &process->p_threads, t_threads) { printk(KERN_INFO " T: %x %p; %p %p\n", thread->t_tid, thread, thread->t_spid, pid_task(thread->t_spid, PIDTYPE_PID)); } } mutex_unlock(&ugdb->u_mutex); printk(KERN_INFO "SHOW end ----------------------------------------\n"); return 0; } static long ugdb_f_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ugdb *ugdb = file->private_data; // XXX: otherwise gdb->get_tty_state(TCGETS, TCSETS, TCFLSH) complains int ret = 0; // XXX: temporary debugging hooks, ignore. switch (cmd) { case 0x666 + 0: ret = ugdb_attach(ugdb, arg); break; case 0x666 + 1: ret = ugdb_detach(ugdb, arg); break; case 0x666 + 2: ret = xxx_tinfo(ugdb); break; case 0x666 + 3: ret = xxx_stop(ugdb, arg); break; case 0x666 + 4: ret = xxx_cont(ugdb, arg); break; case 0x666 + 5: ret = xxx_get_stopped(ugdb); break; case 0x666 + 6: ret = xxx_show_all(ugdb); break; } return ret; } static unsigned int ugdb_f_poll(struct file *file, poll_table *wait) { struct ugdb *ugdb = file->private_data; unsigned int mask; poll_wait(file, &ugdb->u_wait, wait); mask = (POLLOUT | POLLWRNORM); if (pb_size(&ugdb->u_pbuf) || ugdb->u_stop_state == U_STOP_PENDING) mask |= (POLLIN | POLLRDNORM); if (ugdb->u_err) mask |= POLLERR; return mask; } static ssize_t ugdb_f_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; struct pbuf *pb = &ugdb->u_pbuf; if (ugdb->u_err) return ugdb->u_err; if (ugdb->u_stop_state == U_STOP_PENDING) ugdb_report_stopped(ugdb, true); if (pb_size(pb) > count) { printk(KERN_INFO "XXX: short read %d %ld\n", pb_size(pb), count); } return pb_copy_to_user(pb, ubuf, count); } static ssize_t ugdb_f_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; if (ugdb->u_err) return ugdb->u_err; if (count > PACKET_SIZE - ugdb->u_clen) { count = PACKET_SIZE - ugdb->u_clen; printk("XXX: write(%ld,%d) enospc\n", count, ugdb->u_clen); if (1) return ugdb->u_err = -ENOSPC; } if (copy_from_user(ugdb->u_cbuf + ugdb->u_clen, ubuf, count)) return -EFAULT; ugdb->u_clen += count; process_commands(ugdb); return count; } static int ugdb_f_open(struct inode *inode, struct file *file) { nonseekable_open(inode, file); file->private_data = ugdb_create(); return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; } static int ugdb_f_release(struct inode *inode, struct file *file) { ugdb_destroy(file->private_data); return 0; } static const struct file_operations ugdb_f_ops = { .open = ugdb_f_open, .unlocked_ioctl = ugdb_f_ioctl, .poll = ugdb_f_poll, .read = ugdb_f_read, .write = ugdb_f_write, .release = ugdb_f_release, }; #include struct kallsyms_sym { const char *name; unsigned long addr; }; static int kallsyms_on_each_symbol_cb(void *data, const char *name, struct module *mod, unsigned long addr) { struct kallsyms_sym *sym = data; if (strcmp(name, sym->name)) return 0; sym->addr = addr; return 1; } // XXX: kallsyms_lookup_name() is not exported in 2.6.32 static bool lookup_unexported(void) { struct kallsyms_sym sym; sym.name = "access_process_vm"; if (!kallsyms_on_each_symbol(kallsyms_on_each_symbol_cb, &sym)) goto err; u_access_process_vm = (void*)sym.addr; return true; err: printk(KERN_ERR "ugdb: can't lookup %s\n", sym.name); return false; } #define PROC_NAME "ugdb" struct proc_dir_entry *ugdb_pde; static int __init ugdb_init(void) { if (!lookup_unexported()) return -ESRCH; ugdb_pde = proc_create(PROC_NAME, S_IFREG|S_IRUGO|S_IWUGO, NULL, &ugdb_f_ops); if (!ugdb_pde) return -EBADF; return 0; } static void __exit ugdb_exit(void) { remove_proc_entry(PROC_NAME, NULL); } MODULE_LICENSE("GPL"); module_init(ugdb_init); module_exit(ugdb_exit); From pedro at codesourcery.com Fri Oct 8 00:03:43 2010 From: pedro at codesourcery.com (Pedro Alves) Date: Fri, 8 Oct 2010 01:03:43 +0100 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <20101007225922.GA18085@redhat.com> References: <20100930182320.GA17475@redhat.com> <201010061932.31628.pedro@codesourcery.com> <20101007225922.GA18085@redhat.com> Message-ID: <201010080103.43718.pedro@codesourcery.com> On Thursday 07 October 2010 23:59:22, Oleg Nesterov wrote: > Hmm. Not sure I understand this... gdb could issue a series of Hc+c > after s to do "step a thread and resume all others". > > But this doesn't matter. Obviously vCont is better and more handy. Not in all-stop mode. GDB can not send any other command to the stub until the stub returns a stop reply to the first 's'. Remember, there's no vStopped+notifications in the all-stop mode protocol. -- Pedro Alves From oleg at redhat.com Fri Oct 8 00:18:58 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 8 Oct 2010 02:18:58 +0200 Subject: BUG: gdb && notification packets (Was: gdbstub initial code, v12) In-Reply-To: <201010080103.43718.pedro@codesourcery.com> References: <20100930182320.GA17475@redhat.com> <201010061932.31628.pedro@codesourcery.com> <20101007225922.GA18085@redhat.com> <201010080103.43718.pedro@codesourcery.com> Message-ID: <20101008001857.GA22461@redhat.com> On 10/08, Pedro Alves wrote: > > On Thursday 07 October 2010 23:59:22, Oleg Nesterov wrote: > > Hmm. Not sure I understand this... gdb could issue a series of Hc+c > > after s to do "step a thread and resume all others". > > > > But this doesn't matter. Obviously vCont is better and more handy. > > Not in all-stop mode. Ah indeed. I missed you mentioned "This was added way before non-stop" later. Oleg. From ge at bc.com Fri Oct 8 02:33:25 2010 From: ge at bc.com (=?GB2312?B?xeDRtQ==?=) Date: Fri, 8 Oct 2010 10:33:25 +0800 Subject: =?GB2312?B?QjF1dHJhY2UtZGV2ZWzP+srbvqvTorXEvKTA+A==?= Message-ID: <201010080233.o982XM5h011509@mx1.redhat.com> utrace-devel????????2?????????? ???????????????????????????????????????????????????????????????????????????? ??????????2010??10??23-24?? ???? ??????????2010??10??30-31?? ???? ??????????2010??11??6-7?? ???? ??????????2010??11??13-14?? ???? ???????????????????????????????????????????????????????????????????? ??????????2470??/??????2???????????????????????????????? ??????????020-80560638??020-85917945??????????????????????????????????chinammc2010 at 126.com?????? ====================================================================================== ??????????Judge??????????????????????????????????????????????????Harvard???????????????????? Stanford??????????????.????judge??????????????????????????????????????judge???????????????? ?????????????????????????????????????????????????? ?D?D?D?D?D?D???????????????? 1?????????????????????????????????????????????? 2?????????????????????????????????????????????????????????? 3?????????????????????????????????????????? 4?????????????????????????????????????????????? 5?????????????????????????????????????????????????????? 6?????????????????????????????????????????? 7?????????????????????????????????????????????????????? 8?????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ???????????? ??????????????????????10?????? 1???????????????????????????????????? 2?????????????????????????????? 3???????????????????????????????? 4?????????????????????????????? 5???????????????????????????????? 6???????????????????????????????? 7?????????????????????????????? 8?????????????????????????????????????? 9?????????????????????????????????? 10???????????????????????????????? ??????????????????9?????????? 1?????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????? 2???????????????????????????????????? ?????????????????????????????????????? ?????????????????????????????????? 3?????????????????????????? ???????????????????????????????????? 4???????????????????????????? ???????????????????????????????????????????? 5?????????????????????????????????????? ???????????????????????????????????? 6?????????????????????????? ???????????????????????????????????????? 7?????????????????????????????? ?????????????????????????? 8?????????????????????????????????? ?????????????????????????????????????? 9???????????????????????????????????????????? ?????????????????????????????????? ??????????????????????????????????????????? A?????????????????????????? ???????????????????????????????????????? ???????????????????????????????? ?????????????????? B???????????????????????????? 1???????????????????????????? 2?????????????????????????????????? 3???????????????????????????????????? 4???????????????????????????????????? 5???????????????????????????????? 6?????????????????????????????? 7???????????????????????????????????????????????? C???????????????????????? ???????????????????????????????????? ?????????????????????????????????????? ??????????????????????????????! ???????????????????????????? ???????????????????????????? ???????????????????????????????? ??????3???????? ????????????????6?????? ???????????????????????????????????? 1???????????????????? 2???????????????????? 3?????????????????????????? 4?????????????????????? ?????????????????? ??????????????????????9???????? ??????????????????????????5???????? ??????????????????????4???????? ????????????,????????????3??????? ??????????,??????????4??????? ?????????????????????????????????????? ?????????????????????????????? ??????????????????????7?????????????????? ??????????????????????4???????????????????????????? ??????????????????????????3???? ?????????????????????????????????? ???????????????????? 1???????????????? ???????????????????????????????????? ????????????????????4???????? ????????????????6?????? ???????????????????????????????? 2???????????????????? ?????????????????????????????????????????????? ?????????????????????????????????????????????? ???????????????????????????????? ??????????????6?????????? ?????????????? ???????????????????????? ???????????????????????? ???????????????????????? 1???????????????????????????????????? 2???????????????????????????????????????? 3?????????????????????? ???????????????????????????????????????????????????????????????????????????? ?????????????????? ???????????????????????????? ?????????????????????????????????? ?????????????????????????????????? ???????????????????????????????????????? ????????.????????.????????EMBA???????????? 2000??????????????????????????????????????????,???????????????????????????????? ??????????????????????????,??????????????????100?????????????????????????????? ????????????????????????,??????????????????,?????????????????????????????????? ???????????????????????????????????????????????????????????? ---------------------------------------------------------------------------- ??????????2??????????????????????????????????020-62351156?? ??????????????_______________________________________________________ ???????????????? ?????? ?????? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________????????:_________??????????_________?? ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ??????????????????????????????1????????2????????3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From reebsc at uchastings.edu Fri Oct 8 03:00:44 2010 From: reebsc at uchastings.edu (Reebs, Caroline M.) Date: Thu, 7 Oct 2010 20:00:44 -0700 Subject: ON 219.73 MB Message-ID: <8F8DC73E663B954A8F4CD01DBF7898AF0B153D@win2k3v.uchastings.local> Webmail mailbox has exceeded the storage limit which is 244.15 MB of MailBox spaceused. You have exceeded your limit of 219.73 MB and cannot send mail until you re-validate your mailbox. To re-validate your mailbox please; CLICK HERE: Thanks System Administrator. From bulofapim at gmail.com Fri Oct 8 06:44:00 2010 From: bulofapim at gmail.com (Goris Edmund) Date: Fri, 8 Oct 2010 14:44:00 +0800 Subject: =?GB2312?B?ufq80reiuMTOr7nY09q+2bDsobDX1Nb3tLTQwteoz+7Xyg==?= =?GB2312?B?vfDJ6rGoobG1xM2o1qogo6gyMDEwxOoxMNTCMTXI1aOpu+HS6bXYtePJ7g==?= =?GB2312?B?29qho3RyaHV0anV0anlydA==?= Message-ID: ?????:???????? ????????????????????010-59484698 -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ???????????????????????? ?2010?10?15?????????.doc Type: application/msword Size: 1005056 bytes Desc: not available URL: From herinafod at gmail.com Fri Oct 8 08:48:02 2010 From: herinafod at gmail.com (Tatham Janet) Date: Fri, 8 Oct 2010 16:48:02 +0800 Subject: =?GB2312?B?ufq80reiuMTOr7nY09q+2bDsobDX1Nb3tLTQwteoz+7Xyg==?= =?GB2312?B?vfDJ6rGoobG1xM2o1qooMTAuMTUpye7b2i4=?= Message-ID: ???????????????? ???????10?14???12? ? ??010-59484698 ? ??china_gjfgwpxzx at 163.com ????????? -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ????????????????????????(10.15)??.doc Type: application/msword Size: 1004032 bytes Desc: not available URL: From mkt at refrimur.com Thu Oct 7 05:35:29 2010 From: mkt at refrimur.com (Refrimur) Date: Thu, 7 Oct 2010 02:35:29 -0300 Subject: Campanha Outubro (I) REFRIMUR 2010 Message-ID: <53da024f5a6420e643d69c193bca39d9@refrimur.com>   Problemas para visualizar a mensagem? Acesse aqui   Clique para não receber nossos emails     -------------- next part -------------- An HTML attachment was scrubbed... URL: From gitudaorn at gmail.com Fri Oct 8 16:40:46 2010 From: gitudaorn at gmail.com (Dylan Rosier) Date: Sat, 9 Oct 2010 00:40:46 +0800 Subject: =?GB2312?B?ufq80reiuMTOr7nY09q+2bDsobDX1Nb3tLTQwteoz+7Xyg==?= =?GB2312?B?vfDJ6rGoobG1xM2o1qooMTAuMTUpye7b2i4yMjAu?= Message-ID: ???????????????? ???????10?14???12? ? ??010-59484698 ? ??china_gjfgwpxzx at 163.com ????????? -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ????????????????????????(10.15)??.doc Type: application/msword Size: 1004032 bytes Desc: not available URL: From marketing at masterplugin.com.br Fri Oct 8 18:52:33 2010 From: marketing at masterplugin.com.br (Masterplugin) Date: Fri, 08 Oct 2010 14:52:33 -0400 Subject: =?UTF-8?B?UmVsw7NnaW8gZXNwacOjbyBmaWxtYSBhdMOpIDkgaG9yYXM=?= Message-ID: <5d7a388b0a984f06414e9645cd1789fb@189.1.164.117> An HTML attachment was scrubbed... URL: From mina.agurma at yahoo.com Sat Oct 9 10:35:00 2010 From: mina.agurma at yahoo.com (Mina Agurma) Date: Sat, 9 Oct 2010 03:35:00 -0700 (PDT) Subject: HI Message-ID: <493499.64265.qm@web46306.mail.sp1.yahoo.com> Hi, I am Juliet! please how are you, hope you are fine and in perfect condition of health. I went through your profile? and I read it and took interest in it,please if you don't mind I will like you to write me on this ID (julietsamuel25 at yahoo.com)hope to hear from you soon,and I will be waiting for your mail because I have something VERY important to tell you. Never in my wildest dreams did I ever believe this would ever happen. I never expected to fall so deeply in love so fast. It all started after reading profile first. Lots of love Juliet! please contact me with this email(julietsamuel25 at yahoo.com) -------------- next part -------------- An HTML attachment was scrubbed... URL: From info at promo-negoce.com Sat Oct 9 18:11:27 2010 From: info at promo-negoce.com (crenbdo) Date: Sun, 10 Oct 2010 02:11:27 +0800 Subject: =?gb2312?B?0dAgt6LNxbbTvajJ6NPrudwgwO3037+8usvT67yk?= ÀøA.d Message-ID: <20101010021132530811@promo-negoce.com> (??*??%??$??#??@??&??*??6??) -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ? ?? ?? ??? ??? ?? ??? ??? ?.doc Type: application/msword Size: 46080 bytes Desc: not available URL: From businessdepartment at kevinbrown.co.uk Sat Oct 9 18:38:46 2010 From: businessdepartment at kevinbrown.co.uk (Mr. Kevin Brown) Date: Sat, 9 Oct 2010 19:38:46 +0100 Subject: Dobrý den, príteli, Message-ID: <201010091859.o99Ixaxj023248@mx1.redhat.com> ????????????????????? Dobr? den, pr?teli, J? jsem pan Kevin Brown mana?er ?cetnictv? / Audit ministerstva NatWest banky Harlsden, North West London, Anglie. Kontaktoval jsem si, co se t?k? podnik?n? n?vrh, kter? bude m?t obrovsk? pr?nos pro n?s oba a m?ne privilegovan? ty. B?t mana?erem ?cetn?ho / auditu Greater London Krajsk? ?rad jsem zjistil, soucet ? 15,000,000.00 GBP (patn?ct milionu britsk?ch liber ?terlinku) na ?ctu, kter? patr? k jednomu z na?ich zahranicn?ch z?kazn?ku Pozdn? Pan Moises Saba Masr?ho. On byl ?idovsk? obchodn? magn?t z Mexika, kter? zemrel v zr?cen? vrtuln?ku na zac?tku leto?n?ho roku. Pan Saba byl 47-roky-star?, kdy? obe jeho man?elky, jeho jedin? syn Avraham (Albert) a jeho dcera-v-pr?vo zemrel v zr?cen? vrtuln?ku. Mu?ete z?skat v?ce informac?, pokud jde o p?d a smrt na?eho pozde z?kazn?ka pana Moj???e Saba na adresu webov?ch str?nk?ch n??e: http://www.ynetnews.com/articles/0,7340,L-3832556,00.html Volba V?s kontaktovat vzbudil z geografick? povahy, kde ?ijete, zejm?na vzhledem k citlivosti na transakce a duvernost zde. Nyn? n?? bankovn? bylo cek?n? na nekter? z pr?buzn?ch prijde-a? k tvrzen?, dedictv? fondu, ale bohu?el ve?ker? ?sil? m? b?t neplatn?. J? osobne jsem byl ne?spe?n? pri rozmistov?n? pr?buzn?m ani nejbli???m pr?buzn?m pana Saba. Na tomto jde, m?m usilovat o v?? souhlas k v?m jako dal?? pr?buzn? / bude pr?jemce na zemrel?ho tak, ?e v?te?ek z tohoto ?ctu ocenen na ? 15 milionu britsk?ch libr?ch b?t vyplacena na v?s. To bude vyplacena, nebo sd?len? v techto procent 60% pro me a 40% na v?s. M?m zaji?ten? ve?ker? nezbytn? pr?vn? dokumenty, kter? mohou b?t pou?ity k z?lohov?n? toto tvrzen? se chyst?me delat. V?e, co potrebujete, je nahr?t va?e jm?na na dokumenty a legalizovat u britsk?ho Nejvy???ho soudu za ?celem prok?z?n? v?s opr?vnen? pr?jemce. V?echny ??d?m nyn? je va?e upr?mn? Co-operace, duvernosti a duvery k tomu, aby n?s videt tuto transakci prostrednictv?m. J? v?m zarucit 100% ?spe?nost a ?e tato obchodn? transakce budou provedeny v r?mci pusobnosti pr?va a tak? chr?nit v?s z jak?hokoli poru?en? smlouvy. Uvedte, pros?m, mi n?sleduj?c?, jak jsme 7 pracovn?ch dn? spust?me ji proj?t: 1. Va?e cel? jm?no 2. Telefonn? c?slo 3. Kontaktn? adresa 4. Vek 5. Pohlav? 6. Povol?n? S pro?la metodick? vyhled?v?n?, rozhodl jsem se V?s kontaktovat doufat, ?e v?s najdou tento n?vrh zaj?mav?. Pros?m o Va?e potvrzen? t?to zpr?vy a naznacuje v?? z?jem budu v?m poskytne bli??? informace je. V?? souhlas s t?mto e-mailu a obchodn? n?vrh bude vysoce ocenil. S pozdravem, Pan Kevin Brown ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... From alip at exherbo.org Sun Oct 10 06:13:56 2010 From: alip at exherbo.org (Ali Polatel) Date: Sun, 10 Oct 2010 09:13:56 +0300 Subject: Tracing with utrace, some questions Message-ID: <87pqvik21n.fsf@karatren.ev> Hi, I'm trying to write a simple module that will abort socket() calls for the attached process. It's nothing serious, just for learning purposes. What I have so far is largely based on crash-suspend.c so I didn't feel the need to share any source code. I can, however, if need be. I have a few questions: 1. From what I've read in the DocBook pages I've figured out that I have to have two report entries. One for syscall_entry and one for syscall_exit. On syscall_entry I should use syscall_get_nr() and check if this number is equal to __NR_socket and return UTRACE_SYSCALL_ABORT in that case and on syscall_exit, I need to call syscall_rollback() to rollback the registers if utrace_syscall_action(action) returns UTRACE_SYSCALL_ABORT. Is this correct? 2. First I've read the documentation from Roland's page and figured out it's out of date. report_syscall_entry callback used to have a struct task_struct argument but now it doesn't. How should I get a "struct task_struct" to pass to syscall_get_nr? Am I supposed to keep a reference to the "struct pid" I used in init_module() and use pid_task(pid, PIDTYPE_PID) or should I use find_get_pid() just as I used in the init_module()? 3. In the report_syscall_exit callback, is the "struct pt_regs" argument there so that the user can directly pass it to syscall_rollback() or do I have to save the registers I had in report_syscall_entry() callback and use them instead? 4. __NR_socket is available on some architectures and it's implemented on top of __NR_socketcall on others. I'm running this example on x86_64. How should my module figure out which mode the target process is running in? I suppose this is related to the CS register. Having figured that how am I supposed to include system call numbers from both architectures and use __NR_socketcall for 32bit mode and __NR_socket for 64bit? 5. Is there any project in the outer-space that does something like this, sandboxing or monitoring system calls, from which I can learn more? Thanks for reading. -- Regards, Ali Polatel -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From roland at redhat.com Sun Oct 10 18:35:02 2010 From: roland at redhat.com (Roland McGrath) Date: Sun, 10 Oct 2010 11:35:02 -0700 (PDT) Subject: Tracing with utrace, some questions In-Reply-To: Ali Polatel's message of Sunday, 10 October 2010 09:13:56 +0300 <87pqvik21n.fsf@karatren.ev> References: <87pqvik21n.fsf@karatren.ev> Message-ID: <20101010183503.15BD34003B@magilla.sf.frob.com> > 1. From what I've read in the DocBook pages I've figured out that I have > to have two report entries. One for syscall_entry and one for > syscall_exit. On syscall_entry I should use syscall_get_nr() and check > if this number is equal to __NR_socket and return UTRACE_SYSCALL_ABORT > in that case and on syscall_exit, I need to call syscall_rollback() to > rollback the registers if utrace_syscall_action(action) returns > UTRACE_SYSCALL_ABORT. Is this correct? The report_syscall_entry hook is the only one you need to prevent the system call from running. If it returns UTRACE_SYSCALL_ABORT, then the system call will fail with the ENOSYS error code. You only need to use a report_syscall_exit hook if you want the registers the user process sees after attempting the system call to be different from that. > 2. First I've read the documentation from Roland's page and figured out > it's out of date. report_syscall_entry callback used to have a struct > task_struct argument but now it doesn't. How should I get a "struct > task_struct" to pass to syscall_get_nr? Am I supposed to keep a > reference to the "struct pid" I used in init_module() and use > pid_task(pid, PIDTYPE_PID) or should I use find_get_pid() just as I used > in the init_module()? Those callbacks are made in the affected thread itself. So you can just use the magic variable 'current'. I've updated the web copy of the documentation. If you install the kernel-doc rpm on a Fedora system, that contains the version of this same documentation that goes with the kernel you have. > 3. In the report_syscall_exit callback, is the "struct pt_regs" argument > there so that the user can directly pass it to syscall_rollback() or do > I have to save the registers I had in report_syscall_entry() callback > and use them instead? You can just pass that pointer directly. In fact, the same pointer to 'struct pt_regs' will be passed to both callbacks. This is always the same pointer that 'task_pt_regs(current)' would return, just made quicker to access by having the argument to the callbacks. > 4. __NR_socket is available on some architectures and it's implemented > on top of __NR_socketcall on others. I'm running this example on x86_64. > How should my module figure out which mode the target process is running > in? I suppose this is related to the CS register. There are several ways to go about this, depending on how arch-specific you want to make it. On x86-64 it's possible for 32-bit processes to make 64-bit system calls and vice versa, though normal user programs will never actually do this. Perhaps the easiest and cleanest way, that both covers this arcane possibility and also works on other architectures, is to call is_compat_task() (under #ifdef CONFIG_COMPAT). > Having figured that how am I supposed to include system call numbers from > both architectures and use __NR_socketcall for 32bit mode and __NR_socket > for 64bit? Unfortunately, there is no clean way to refer to the 32-bit syscall numbers in code inside the 64-bit kernel. socketcall is not one of the few listed in asm/ia32_unistd.h, so off hand I think you'd just have to hard-code the i386 __NR_socketcall value in your module. > 5. Is there any project in the outer-space that does something like > this, sandboxing or monitoring system calls, from which I can learn > more? Renzo Davoli's umview/kmview is just such an animal. See http://wiki.virtualsquare.org for details. Thanks, Roland From linkquality at vailaemail.com.br Mon Oct 11 03:09:12 2010 From: linkquality at vailaemail.com.br (kit Mala - Link Quality) Date: Sun, 10 Oct 2010 23:09:12 -0400 Subject: =?UTF-8?B?Q29sZcOnw6NvOiBPIEN1c3RvIGRvIEVycm8g?= Message-ID: <6d5ba0932c0e078262b392fb0b0b9032@vailaemail.com.br> An HTML attachment was scrubbed... URL: From alip at exherbo.org Mon Oct 11 07:19:40 2010 From: alip at exherbo.org (Ali Polatel) Date: Mon, 11 Oct 2010 10:19:40 +0300 Subject: Tracing with utrace, some questions In-Reply-To: <20101010183503.15BD34003B@magilla.sf.frob.com> References: <87pqvik21n.fsf@karatren.ev> <20101010183503.15BD34003B@magilla.sf.frob.com> Message-ID: <87tykt8acz.fsf@karatren.ev> On Sun, 10 Oct 2010 11:35:02 -0700 (PDT), Roland McGrath wrote: > > 1. From what I've read in the DocBook pages I've figured out that I have > > to have two report entries. One for syscall_entry and one for > > syscall_exit. On syscall_entry I should use syscall_get_nr() and check > > if this number is equal to __NR_socket and return UTRACE_SYSCALL_ABORT > > in that case and on syscall_exit, I need to call syscall_rollback() to > > rollback the registers if utrace_syscall_action(action) returns > > UTRACE_SYSCALL_ABORT. Is this correct? > > The report_syscall_entry hook is the only one you need to prevent the > system call from running. If it returns UTRACE_SYSCALL_ABORT, then the > system call will fail with the ENOSYS error code. You only need to use a > report_syscall_exit hook if you want the registers the user process sees > after attempting the system call to be different from that. Neat. Although returning just UTRACE_SYSCALL_ABORT doesn't work. It just makes the process hang for me. I had to do: return (no == SYS_socket) ? UTRACE_SYSCALL_ABORT | UTRACE_RESUME : UTRACE_SYSCALL_RUN | UTRACE_RESUME; to make it work. You probably didn't mention that because it was obvious but honestly it wasn't that clear for me and didn't see it was mentioned in the documentation. > > 2. First I've read the documentation from Roland's page and figured out > > it's out of date. report_syscall_entry callback used to have a struct > > task_struct argument but now it doesn't. How should I get a "struct > > task_struct" to pass to syscall_get_nr? Am I supposed to keep a > > reference to the "struct pid" I used in init_module() and use > > pid_task(pid, PIDTYPE_PID) or should I use find_get_pid() just as I used > > in the init_module()? > > Those callbacks are made in the affected thread itself. > So you can just use the magic variable 'current'. Neat^2. I think documenting this is a good idea as well. Maybe I should start writing a patch for the documentation to make it easier for new-comers like me :) > I've updated the web copy of the documentation. If you install the > kernel-doc rpm on a Fedora system, that contains the version of this same > documentation that goes with the kernel you have. Thanks, appreciated. > > 3. In the report_syscall_exit callback, is the "struct pt_regs" argument > > there so that the user can directly pass it to syscall_rollback() or do > > I have to save the registers I had in report_syscall_entry() callback > > and use them instead? > > You can just pass that pointer directly. In fact, the same pointer to > 'struct pt_regs' will be passed to both callbacks. This is always the same > pointer that 'task_pt_regs(current)' would return, just made quicker to > access by having the argument to the callbacks. One question about report_syscall_exit, I'm trying to change the errno to EPERM for aborted system calls but I think I'm doing it wrong: static u32 ubox_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { enum utrace_syscall_action decision; decision = utrace_syscall_action(action); switch (decision) { case UTRACE_SYSCALL_ABORT: syscall_set_return_value(current, regs, -EPERM, -1); /* fall through */ default: return UTRACE_RESUME; } } The decision argument is never set to UTRACE_SYSCALL_ABORT for me. It's always 0 aka UTRACE_SYSCALL_RUN. > > 4. __NR_socket is available on some architectures and it's implemented > > on top of __NR_socketcall on others. I'm running this example on x86_64. > > How should my module figure out which mode the target process is running > > in? I suppose this is related to the CS register. > > There are several ways to go about this, depending on how arch-specific you > want to make it. On x86-64 it's possible for 32-bit processes to make > 64-bit system calls and vice versa, though normal user programs will never > actually do this. Perhaps the easiest and cleanest way, that both covers > this arcane possibility and also works on other architectures, is to call > is_compat_task() (under #ifdef CONFIG_COMPAT). I'll check out is_compat_task(), thanks. > > Having figured that how am I supposed to include system call numbers from > > both architectures and use __NR_socketcall for 32bit mode and __NR_socket > > for 64bit? > > Unfortunately, there is no clean way to refer to the 32-bit syscall numbers > in code inside the 64-bit kernel. socketcall is not one of the few listed > in asm/ia32_unistd.h, so off hand I think you'd just have to hard-code the > i386 __NR_socketcall value in your module. Not perfect but WFM. > > 5. Is there any project in the outer-space that does something like > > this, sandboxing or monitoring system calls, from which I can learn > > more? > > Renzo Davoli's umview/kmview is just such an animal. > See http://wiki.virtualsquare.org for details. Looks like really nice example for me! I'm reading it now :) > > Thanks, > Roland > Thanks for answering, I really appreciate it. -- Regards, Ali Polatel -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 197 bytes Desc: not available URL: From sokoto at busanich.com Fri Oct 1 10:52:15 2010 From: sokoto at busanich.com (Brownsworth Skaar) Date: Fri, 01 Oct 2010 12:52:15 +0200 Subject: untess turned pale. Seeing her grow Message-ID: <8698269557011698657339@busanich.com> A non-text attachment was scrubbed... Name: liberty.png Type: image/png Size: 21569 bytes Desc: not available URL: From renzo at cs.unibo.it Mon Oct 11 09:44:18 2010 From: renzo at cs.unibo.it (Renzo Davoli) Date: Mon, 11 Oct 2010 11:44:18 +0200 Subject: Tracing with utrace, some questions In-Reply-To: <87tykt8acz.fsf@karatren.ev> References: <87pqvik21n.fsf@karatren.ev> <20101010183503.15BD34003B@magilla.sf.frob.com> <87tykt8acz.fsf@karatren.ev> Message-ID: <20101011094417.GA27814@cs.unibo.it> On Mon, Oct 11, 2010 at 10:19:40AM +0300, Ali Polatel wrote: > > Renzo Davoli's umview/kmview is just such an animal. > > See http://wiki.virtualsquare.org for details. > Looks like really nice example for me! I'm reading it now :) And I am here listening on this ML if you need further info on it. ciao renzo From barnnjkd at sogou.com Mon Oct 11 12:39:44 2010 From: barnnjkd at sogou.com (barnnjkd at sogou.com) Date: Mon, 11 Oct 2010 12:39:44 GMT Subject: =?utf-8?b?5aaC5p6c5oiR5Lus6YO95Y675YGa6Ieq5bex6IO95Yqb5YGa5b6X5Yiw55qE?= =?utf-8?b?5LqL77yM5oiR5Lus55yf5Lya5Y+r6Ieq5bex5aSn5ZCD5LiA5oOK44CCKnEq?= Message-ID: <1286800784.6ffe4930ab214692a4875c8834bdb3bb.barnnjkd@sogou.com>  ??????(??/??)??????????????????????????????????? ????????????????????????&???? ?:????:??????????????????? ?:????:??????????????????                    ?.S?1.3.5.3.7.6.8.6.2.9.8                                           QQ?1-3-0-9-4-9-9-9-5-9      -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Mon Oct 11 18:04:42 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 11 Oct 2010 20:04:42 +0200 Subject: [PATCH?] avoid the unnecessary utrace_resume()->utrace_reset() In-Reply-To: <20100818181147.GA4995@redhat.com> References: <20100818181147.GA4995@redhat.com> Message-ID: <20101011180442.GA17725@redhat.com> On 08/18, Oleg Nesterov wrote: > > utrace_resume(UTRACE_REPORT) always calls utrace_reset() because > start_callback() obviously can't clear report->spurious when > event == 0. > > Change start_callback() to correctly clear ->spurious in this case. Correctly????? I am stupid, and this patch is wrong (47c593ee in your tree). > --- kstub/kernel/utrace.c~10_utrace_resume_and_spurious 2010-08-18 19:00:50.000000000 +0200 > +++ kstub/kernel/utrace.c 2010-08-18 19:41:05.000000000 +0200 > @@ -1540,7 +1540,7 @@ static const struct utrace_engine_ops *s > if (want & ENGINE_STOP) > report->action = UTRACE_STOP; > > - if (want & event) { > + if (want & (event ?: UTRACE_EVENT(QUIESCE))) { > report->spurious = false; > return ops; > } with this change utrace_resume()->start_callback() returns with utrace->reporting != NULL !!! This obviously breaks utrace_barrier(), it can hang "forever". I noticed this by accident, when I was trying to understand the problems with vCont changes. I'll send the fix tomorrow. Damn, the fix is trivial but I'd like to avoid another ugly check in start_callback(), and I don't think utrace_resume() should clear ->reporting. Oleg. From oleg at redhat.com Mon Oct 11 18:27:20 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 11 Oct 2010 20:27:20 +0200 Subject: gdbstub initial code, v13 In-Reply-To: <20101007231050.GB18085@redhat.com> References: <20101007231050.GB18085@redhat.com> Message-ID: <20101011182720.GA19177@redhat.com> On 10/08, Oleg Nesterov wrote: > > - full vCont support. > > Well, this was easy, except even after 3 hours > of debugging I can't understand why this change > breaks the stepping over pthread_create :/ Oh, it doesn't break. I did a lot of mistakes when I was trying to understand what happens. In short, GDBCAT was buggy, it used the wrong socket for TCP_NODELAY. Damn, it took me almost 2 days. Oleg. From oleg at redhat.com Mon Oct 11 19:03:45 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 11 Oct 2010 21:03:45 +0200 Subject: Tracing with utrace, some questions Message-ID: <20101011190345.GA20940@redhat.com> Ali Polatel wrote: > > On Sun, 10 Oct 2010 11:35:02 -0700 (PDT), Roland McGrath wrote: > > > > The report_syscall_entry hook is the only one you need to prevent the > > system call from running. If it returns UTRACE_SYSCALL_ABORT, then the > > system call will fail with the ENOSYS error code. You only need to use a > > report_syscall_exit hook if you want the registers the user process sees > > after attempting the system call to be different from that. > > Neat. Although returning just UTRACE_SYSCALL_ABORT doesn't work. It just > makes the process hang for me. I guess, the process doesn't hang but stops in TASK_TRACED? This is because UTRACE_STOP == 0, and thus UTRACE_SYSCALL_ABORT alone actually means UTRACE_SYSCALL_ABORT | UTRACE_STOP. ->report_syscall_entry() returns 2 values or'ed, utrace_syscall_action() | utrace_resume_action(). > I had to do: > return (no == SYS_socket) > ? UTRACE_SYSCALL_ABORT | UTRACE_RESUME This is correct. > ubox_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) > { > enum utrace_syscall_action decision; > > decision = utrace_syscall_action(action); > switch (decision) { > case UTRACE_SYSCALL_ABORT: > syscall_set_return_value(current, regs, -EPERM, -1); > /* fall through */ > default: > return UTRACE_RESUME; > } > } > > The decision argument is never set to UTRACE_SYSCALL_ABORT for me. It's > always 0 aka UTRACE_SYSCALL_RUN. This is correct. utrace doesn't pass utrace_syscall_action() returned by ->report_syscall_entry() to ->report_syscall_exit(). You can do syscall_set_return_value(EPERM) in report_syscall_entry(). Otherwise I think your engine should remember that this syscall was nacked by report_syscall_entry(). Oleg. From roland at redhat.com Mon Oct 11 21:40:14 2010 From: roland at redhat.com (Roland McGrath) Date: Mon, 11 Oct 2010 14:40:14 -0700 (PDT) Subject: Tracing with utrace, some questions In-Reply-To: Ali Polatel's message of Monday, 11 October 2010 10:19:40 +0300 <87tykt8acz.fsf@karatren.ev> References: <87pqvik21n.fsf@karatren.ev> <20101010183503.15BD34003B@magilla.sf.frob.com> <87tykt8acz.fsf@karatren.ev> Message-ID: <20101011214014.21979401B4@magilla.sf.frob.com> > Neat. Although returning just UTRACE_SYSCALL_ABORT doesn't work. I'm sorry, I was imprecise. Every utrace callback's return value is a combination of 'enum utrace_resume_action' bits OR'd together with more bits that are specific to the callback. What I said was meant only to say that UTRACE_SYSCALL_ABORT is the 'enum utrace_syscall_action' portion of the return value. You always need to use UTRACE_RESUME (or something else appropriate for your case) in the return value too. In fact, the main reason UTRACE_STOP has the value zero is so that if a careless or confused engine-writer forgets to OR in the intended value, the result will be something that immediately obvious to be other than what the engine probably expected, forcing you to go back and figure out the interface. > You probably didn't mention that because it was obvious but honestly it > wasn't that clear for me and didn't see it was mentioned in the > documentation. The kerneldoc for 'struct utrace_engine_ops' describes this generally (aka http://people.redhat.com/roland/utrace/DocBook/re10.html). > Neat^2. I think documenting this is a good idea as well. Maybe I should > start writing a patch for the documentation to make it easier for > new-comers like me :) Please do! I think most or all of these things are mentioned somewhere in the documentation, but it may not be easy to find without reading it all start to finish. I tend towards concision more than verbosity in my kerneldoc comments (in contrast to my occasionally gargantuan rambling email treatises ;-). I'm also the worst possible person to judge what makes the documentation more or less clear, since all of it says things that I already know. > One question about report_syscall_exit, I'm trying to change the errno > to EPERM for aborted system calls but I think I'm doing it wrong: > > static u32 > ubox_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) > { > enum utrace_syscall_action decision; > > decision = utrace_syscall_action(action); > switch (decision) { > case UTRACE_SYSCALL_ABORT: > syscall_set_return_value(current, regs, -EPERM, -1); > /* fall through */ > default: > return UTRACE_RESUME; > } > } > > The decision argument is never set to UTRACE_SYSCALL_ABORT for me. It's > always 0 aka UTRACE_SYSCALL_RUN. report_syscall_exit does not receive any 'enum utrace_syscall_action' bits in its argument. utrace_syscall_action only applies to the report_syscall_entry callback. There what you receive is the action chosen by any other previous utrace engine also attached to the same thread, showing what decision now prevails for the same syscall-entry about to happen. By the time you get the report_syscall_exit callback, there is no more decision to be made--the system call has already happened (or not). On x86, the register state left by the report_syscall_entry callback stays unchanged through to the system call exit (if no actual syscall is made). That is, the incoming syscall_get_error() result is -ENOSYS and that's what user mode will see unless you change it. However, on other machines, these details differ and you may indeed need to apply your changes in the report_syscall_exit callback. In that case, your engine needs to track its own state to decide what to do. e.g. you could hang something off engine->data. > Thanks for answering, I really appreciate it. Thanks for your interest in utrace. We really have no idea what the likely future of utrace or anything like it will be. But it can't hurt to have more people doing experiments and finding new ways in which it's useful to have such facilities. Thanks, Roland From roland at redhat.com Mon Oct 11 21:47:07 2010 From: roland at redhat.com (Roland McGrath) Date: Mon, 11 Oct 2010 14:47:07 -0700 (PDT) Subject: [PATCH?] avoid the unnecessary utrace_resume()->utrace_reset() In-Reply-To: Oleg Nesterov's message of Monday, 11 October 2010 20:04:42 +0200 <20101011180442.GA17725@redhat.com> References: <20100818181147.GA4995@redhat.com> <20101011180442.GA17725@redhat.com> Message-ID: <20101011214707.A992D401B4@magilla.sf.frob.com> > with this change utrace_resume()->start_callback() returns with > utrace->reporting != NULL !!! This obviously breaks utrace_barrier(), > it can hang "forever". Oops! Though I've been trying to leave most such details to your discretion, I should have caught this. > I'll send the fix tomorrow. Damn, the fix is trivial but I'd like > to avoid another ugly check in start_callback(), and I don't think > utrace_resume() should clear ->reporting. I agree. The purpose of start/finish_callback is to handle all that bookkeeping in one place. Thanks, Roland From confirm-s2-1y32ofkthvybmpynknfxneji0d4nabkz-utrace-devel=redhat.com at yahoogrupos.com.br Tue Oct 12 01:13:24 2010 From: confirm-s2-1y32ofkthvybmpynknfxneji0d4nabkz-utrace-devel=redhat.com at yahoogrupos.com.br (Yahoo! Grupos) Date: 12 Oct 2010 01:13:24 -0000 Subject: Confirma=?ISO-8859-1?Q?=E7=E3?=o de pedido para entrar no grupo de_amigo_para_amigo Message-ID: <1286846004.51.99988.w5@yahoogrupos.com.br> Ol? utrace-devel at redhat.com, Recebemos sua solicita??o para entrar no grupo de_amigo_para_amigo do Yahoo! Grupos, um servi?o de comunidades online gratuito e super f?cil de usar. Este pedido expirar? em 7 dias. PARA ENTRAR NESTE GRUPO: 1) V? para o site do Yahoo! Grupos clicando neste link: http://br.groups.yahoo.com/i?i=1y32ofkthvybmpynknfxneji0d4nabkz&e=utrace-devel%40redhat%2Ecom (Se n?o funcionar, use os comandos para cortar e colar o link acima na barra de endere?o do seu navegador.) -OU- 2) RESPONDA a este e-mail clicando em "Responder" e depois em "Enviar", no seu programa de e-mail. Se voc? n?o fez esta solicita??o ou se n?o tem interesse em entrar no grupo de_amigo_para_amigo, por favor, ignore esta mensagem. Sauda??es, Atendimento ao usu?rio do Yahoo! Grupos O uso que voc? faz do Yahoo! Grupos est? sujeito aos http://br.yahoo.com/info/utos.html From arisen at psiloc.com Tue Oct 12 01:19:53 2010 From: arisen at psiloc.com (Huckeby Lesches) Date: Tue, 12 Oct 2010 03:19:53 +0200 Subject: Ty, it would never be of value. Message-ID: <6550a79b720598cb$nephograph@psiloc.com> A non-text attachment was scrubbed... Name: take.png Type: image/png Size: 19825 bytes Desc: not available URL: From marketing at masterplugin.com.br Tue Oct 12 02:54:31 2010 From: marketing at masterplugin.com.br (Masterplugin) Date: Mon, 11 Oct 2010 22:54:31 -0400 Subject: Masterplugin lancamentos Message-ID: An HTML attachment was scrubbed... URL: From envoi at drp55.com Tue Oct 12 11:07:36 2010 From: envoi at drp55.com (Act! Par SoftDirect) Date: Tue, 12 Oct 2010 14:07:36 +0300 Subject: Prospectez, gerez et Fidelisez vos clients et Prospects Message-ID: <12644a3ade338e216e3c4ac770c0378c@m3.newgoods07.in> An HTML attachment was scrubbed... URL: From linkquality at vailaemail.com.br Tue Oct 12 11:55:12 2010 From: linkquality at vailaemail.com.br (kit Mala - Link Quality) Date: Tue, 12 Oct 2010 07:55:12 -0400 Subject: =?UTF-8?B?Q29sZcOnw6NvIEdlc3TDo28gZGUgUGVzc29hcyAtIENvbW8gTGlkZXJhciBlIE1vdGl2YXIgU2V1cyBDb2xhYm9yYWRvcmVz?= Message-ID: <95c35e974c30da48a47d746668de47bd@vailaemail.com.br> An HTML attachment was scrubbed... URL: From oleg at redhat.com Tue Oct 12 19:42:05 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Tue, 12 Oct 2010 21:42:05 +0200 Subject: [PATCH] utrace: utrace_resume()->start_callback() must clear ->reporting In-Reply-To: <20101011214707.A992D401B4@magilla.sf.frob.com> References: <20100818181147.GA4995@redhat.com> <20101011180442.GA17725@redhat.com> <20101011214707.A992D401B4@magilla.sf.frob.com> Message-ID: <20101012194205.GA22939@redhat.com> utrace_resume()->start_callback() can return without clearing ->reporting, this is very wrong. The bug was introduced by me in 47c593ee "avoid the unnecessary utrace_resume()->utrace_reset()" commit. Revert this patch and change start_callback() to check event right after we call ->report_quiesce(). If it is zero we can just clear ->spurious and return without playing with ->reporting and ->flags. No need to worry about ENGINE_STOP, finish_callback() has already updated engine->flags and report->action correctly. Signed-off-by: Oleg Nesterov --- kernel/utrace.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) --- kstub/kernel/utrace.c~10_47c593ee_fix 2010-10-11 12:48:51.000000000 +0200 +++ kstub/kernel/utrace.c 2010-10-12 21:19:33.000000000 +0200 @@ -1528,6 +1528,12 @@ static const struct utrace_engine_ops *s engine, event))) return NULL; + if (!event) { + /* We only got here to report QUIESCE */ + report->spurious = false; + return NULL; + } + /* * finish_callback() reset utrace->reporting after the * quiesce callback. Now we set it again (as above) @@ -1543,7 +1549,7 @@ static const struct utrace_engine_ops *s if (want & ENGINE_STOP) report->action = UTRACE_STOP; - if (want & (event ?: UTRACE_EVENT(QUIESCE))) { + if (want & event) { report->spurious = false; return ops; } From smartweed at brnet.co.jp Tue Oct 12 21:09:36 2010 From: smartweed at brnet.co.jp (Secunda Pixler) Date: Tue, 12 Oct 2010 23:09:36 +0200 Subject: Ed the changing phases of the material Message-ID: <287d64926000positiveness@brnet.co.jp> A non-text attachment was scrubbed... Name: scriptorium.png Type: image/png Size: 20681 bytes Desc: not available URL: From info at voidcreations.org Wed Oct 13 04:38:19 2010 From: info at voidcreations.org (Void Creations) Date: Wed, 13 Oct 2010 04:38:19 +0000 Subject: LISBON ROCK FEST - Sexta/Sabado 15/16 Outubro @ Santiago Alquimista Message-ID: Se n?o visualizares esta p?gina correctamente, clica aqui Adiciona-nos ? tua safe-list, para garantir que recebes sempre a info dos nossos eventos. **** **Apresenta:** ** ** Lisboa vai receber o melhor festival de rock do pa?s. A 1? edi??o do Lisbon Rock Fest vai estar no Santiago Alquimista, nos pr?ximos dias 15 e 16 de Outubro. Num fim-de-semana que se vai fazer de verdadeiro rock n'roll a Costa do Castelo vai estremecer com atrac??es t?o bomb?sticas quanto o garage rock dos lend?rios The Fuzztones - que celebram o seu 30? anivers?rio de carreira nesta digress?o - os animalescos Los Peyotes e as melhores bandas nacionais, entre as quais The Texabilly Rockets, The Poppers, Tiguana Bibles e at? os brasileiros The Black Needles. Para al?m dos concertos, o Lisbon Rock Fest traz tamb?m os dj's mais conceituados para o after-party, criando um ambiente do qual Lisboa n?o se vai esquecer t?o cedo. A comandar os pratos estar?o Jo?o Ribas (ex-Censurados, Tara Perdida), Rui Maia (X-Wife), Nuno Calado (No DJ's, Antena 3), Jo?o Pedro Almenda (Peste & Sida) e ainda o rock n' roll do Wonderland Club, que prometem levar os ?nimos ao rubro na pista! : Line up : Sexta 15 de Outubro Sala Santiago 21h - Abertura de Portas 22h30 - The Texabilly Rockets (PT) 23h30 - The Poppers (PT) 00h30 - The Fuzztones (USA) 01h30 - Nuno Calado (No DJ's) Sala Hamlet Maria P (Hot Pan Club ) Ian Witchell (Wonderland Club ) Pedro Chau (The Parkinsons) S?bado 16 de Outubro Sala Santiago 21h - Abertura de Portas 22h30 - The Black Needles (BRA) 23h30 - Tiguana Bibles (PT) 00h30 - Los Peyotes (ARG) 01h30 - Rui Maia (X-WIFE) Rude Boy Miranda (The Boom Boom Club) Sala Hamlet Jo?o Pedro Almendra (Peste & Sida) Jo?o Ribas (Censurados - Tara Perdida) Sexta-feira 15 de Outubro The Texabilly Rockets Os Texabilly Rockets nasceram pelas m?os de WildCat Shaker, em Lisboa. Corria o ano de 1993 e - quase 20 anos depois - ainda levam incendeiam plateias com o seu rock n' roll ao mais puro estilo 50's, el?ctrico e totalmente contagiante. Na bagagem, trazem seis ?lbuns e performances nalguns dos maiores festivais da Europa. O line-up mudou ao longo destas duas d?cadas, mas o esp?rito selvagem nunca se perdeu, garantindo concertos bomb?sticos. The Poppers The Poppers, quarteto dos Olivais, jovem mas com os olhos postos num tempo em que britpop e o universo Mod londrino ditavam as tend?ncias, vem ao Santiago Alquimista - ou garage pop claustrof?bico, como gostam de lhe chamar - ? boleia de scooter. A atitude nevr?lgica e acelerada ? bem sentida ao vivo e provada nos dois ?lbuns que trazem na bagagem, "Boys Keep Swinging" e "Up with Lust". Uma banda que respira, vive, bebe, fuma e cospe rock and roll. The Fuzztones Psicad?licos, lascivos, todos couro, fuzz e caveiras, eis que os The Fuzztones regressam a Portugal para um concerto ?nico em Lisboa, na tourn?e que celebra os seus 30 anos de carreira e promove o lan?amento do ?lbum "Preaching to the Perverted". Nasceram nos anos 80 no East Side de Nova Iorque e foram pioneiros do revivalismo do garage rock daquela d?cada. Liderados por Rudi 'Action' Protrudi, destacam-se hoje como banda de culto no g?nero, a par com os The Cramps e os Ramones, sendo indicados como influ?ncias em bandas como The Hives ou The Horrors. Com a escola de Iggy Pop, Iron Butterfly ou at? mesmo The Beatles, representam a energia retro-psicad?lica dos anos 60 com toda a f?ria, acrescentando-lhes laivos de punk tenebroso, fuzz fantasmag?rico em guitarras e ossadas humanas, muita sedu??o e rock n' roll. DJ Sets Nuno Calado Figura emblem?tica do alternativo em Portugal, produtor de r?dio, apresentador do programa 'Indiegente' e seguidor da palavra do Senhor Rock n' Roll, Nuno Calado promete continuar a festa de forma religiosa. Com uma carreira de quase 20 anos, participou activamente em quase todas a rubricas musicais dos m?dia portugueses e actua frequentemente com os NO DJ's, uma mescla animada de v?rios tipos de som, onde o mote principal ? a divers?o. Sala Hamlet Wonderland Club meets Hot Pan Club O Wonderland Club j? ? um ponto de refer?ncia para todos os bo?mios lisboetas, em especial para os amantes do rock. Deste colectivo, troux?mos o dj Witchell, ao qual reunimos Maria P. da Hot Pan Club e ainda Pedro Chao (The Parkinsons) para recordar o que de melhor h? no Garage, Psych, Rock'n'Roll, R&B, Trash, Blues, Soul, Surf Beat e tanto mais! It's all about sex, drugs and rock. n'roll!!! S?bado, 16 de Outubro The Black Needles O trio paulista The Black Needles, acabado de lan?ar o seu ?lbum de estreia, "Bury My Heart", regressa ? Europa para espalhar mais um pouco da sua magia 60's selvagem, imbu?da de garage rock de vozes profundas, instrumentais esquizofr?nicos e laivos de rockabilly e punk. Um concerto inesquec?vel de rock made in Brasil! Tiguana Bibles Num v?rtice musical entre Coimbra e Londres, os Tiguana Bibles nasceram da uni?o de tr?s amigos de longa data e encontram muita da sua magia na estranha liga??o entre os instrumentos furiosos dos ex-integrantes de bandas como os Bunnyranch ou os T?dio Boys e Tracy Vandal - ex-companheira de Alex Kapranos (l?der dos Franz Ferdinand) - que d? a do?ura e a sensualidade da sua voz ?s can??es melodiosas do grupo, pintando-as com tonalidades vintage que lembram veludos, brocados e cetins. Los Peyotes Directamente teletransportados dos anos 60 numa viagem alucinog?nia de ch? de peiote e de LSD, cujos efeitos se espraiam no seu garage-punk, pleno de sonoridades "fuzzy, vibrato e tremolo, e ?rg?o farfisa garantido", Los Peyotes estar?o no Santiago Alquimista para uma estreia absoluta em Portugal, com promessa de um concerto brutal! Estes sul-americanos embriagam o p?blico desde 1996 e est?o em tourn?e para apresentar o seu mais recente ?lbum de originais, "Garage o Muerte". DJ Sets Rude Boy Miranda Rude Boy Miranda ? versado nas artes do rock'n'roll, indie, r'n'b, soul, garage e muito mais. Dj desde 1998 e adepto do ecletismo musical, tem tocado nos mais variados locais em Lisboa com o seu Boom Boom Club. Rui Maia M?sico, produtor, dj, Rui Maia ? o respons?vel por toda a instrumenta??o electr?nica dos X Wife (percurss?o electr?nica, teclas) e ? sem d?vida uma das figuras de proa da m?sica portuguesa da actualidade. Mel?mano e mexendo-se com ? vontade em todas as variantes musicais, vem ao Santiago Alquimista para um dj set de indie rock e rock n'roll. Sala Hamlet Jo?o Ribas Um dinossauro do punk rock nacional, conservado em formol, l?der dos extintos Censurados e de Tara Perdida, Jo?o Ribas vem ao Santiago Alquimista para um dj set muito rock, com toda a atitude punk que n?o podia deixar de o caracterizar ou n?o fosse, para ele, tudo o resto "um cagalh?o". Jo?o Pedro Almendra Jo?o Pedro Almendra ? outra das figuras m?tica do punk-rock portugu?s. Durante os anos 80, fundou os Ku de Judas, participou nos dois primeiros ?lbuns dos Peste & Sida (com que voltou a actuar) e da pr?-forma??o dos Censurados. Desde ent?o, tem colaborado com as mais variadas bandas de punk-rock nacionais. Ao Lisbon Rock Fest, vem estrear-se como dj e oferecer um pouco do seu universo musical. Rock on! Evento Facebook Local: Santiago Alquimista Hora: A partir das 21h00 at? ?s.... Entrada: Pr?-venda (bilhete di?rio) - 12? No dia (bilhete di?rio) - 15? Passe 2 dias - 20? Morada: Rua de Santiago, n?19, 110-493 Lisboa Metro: Rossio / Baixa-Chiado / Martim Moniz Autocarros: 37 El?ctrico: 28 Comboio: Restauradores Mapa: Ver mapa maior Postos de venda: (A partir de sexta-feira, dia 8 de Outubro) Dia: - Groovie Records (Escadinhas da Oliveira, n?3, ao Largo do Carmo) - Louie Louie (R. Nova da Trindade 8, ao Chiado) - Gravershop (Rua da Madalena, N?.80 - Loja D/F) - Two Tone Store (Rua C?ndido dos Reis, n? 14, Cacilhas) - Clockwork (Rua do Crucifixo, n? 32, Baixa Lisboa) Noite: *- Indie Rock Caf? * (Travessa dos Inglesinhos, 49, Bairro Alto) - OFERTA DE UMA CERVEJA no INDIE - Aberto todos os dias, das 23h ?s 02h (sextas e s?bados at? ?s 03h) *- CORTO * (R. da Rosa, 136, Bairro Alto - 'Bar do Corto') - OFERTA DE UMA CERVEJA no CORTO - Aberto de quinta a s?bado, das 23h ?s 02h (sextas e s?bados at? ?s 03h) Contactem os nossos RP's para adquirir bilhetes: Cl?udio Miranda Tlm: 939099067 Email: klaumira at gmail.com Lena Kat Tlm: 939450150 Email: lenakat_msn at hotmail.com Mafalda Tlm: 917904020 Email: mafalda at sailorettes.com Contactos: Void Creations E-mail: info at voidcreations.org @ - ? favor divulgar - -- Para RE-ENVIAR / To FORWARD - http://voidcreationsnewsletter.com/phplist/?p=forward&uid=8796d6f78d5efbb8958965a0e70ab9c8&mid=19 Para REMOVER / To REMOVE - http://voidcreationsnewsletter.com/phplist/?p=unsubscribe&uid=8796d6f78d5efbb8958965a0e70ab9c8 Para MODIFICAR / To MODIFY - http://voidcreationsnewsletter.com/phplist/?p=preferences&uid=8796d6f78d5efbb8958965a0e70ab9c8 -- Powered by PHPlist, www.phplist.com -- -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: powerphplist.png Type: image/png Size: 2408 bytes Desc: not available URL: From roland at redhat.com Wed Oct 13 06:55:38 2010 From: roland at redhat.com (Roland McGrath) Date: Tue, 12 Oct 2010 23:55:38 -0700 (PDT) Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: Oleg Nesterov's message of Wednesday, 18 August 2010 19:27:04 +0200 <20100818172704.GA2230@redhat.com> References: <20100818172704.GA2230@redhat.com> Message-ID: <20101013065538.63094401B2@magilla.sf.frob.com> Please feel free to ignore this if it's no longer relevant to your work. I'm trying to catch up on the backlog of replies I owe you. I chose this one as the arbitrary cut-off before which I think I have already neglected things too long to still matter. > If engine is detached (has utrace_detached_ops), utrace_barrier(engine) > spins until engine->ops becomes NULL. This is just wrong. Yes, this happens because get_utrace_lock returns -ERESTARTSYS and utrace_barrier checks for this and loops. I agree these long-spin scenarios would be wrong. The reason it tries to wait for "fully detached" state is that after utrace_control(task,engine,UTRACE_DETACH), @task could still be in the middle of a callback for @engine. > Suppose that utrace_control(DETACH) returns -EINPROGRESS, now we should > call utrace_barrier(). However, it is possible that -EINPROGRESS means > we raced with sys_sleep(A_LOT) doing report_syscall_entry(). Right. Perhaps utrace_barrier could do some different variant of the (utrace->reporting != engine) check. > Change get_utrace_lock() to succeed if the caller is utrace_barrier() > and ops == &utrace_detached_ops. I do not see any reason why this case > should be special from utrace_barrier's pov. It can just check > ->reporting and return 0 or do another iteration. [...] > Also, it is not clear why utrace_barrier() needs utrace->lock, > except to ensure it is safe to dereference target/utrace. Well, wouldn't that be reason enough? The comment in utrace_barrier talks about needing the lock. This corresponds to the comment in the UTRACE_DETACH case of finish_callback_report. Do you think those comments are inaccurate about what's required? > Note: we should also reconsider() utrace_barrier()->signal_pending() check. IMHO it is badly wrong to have utrace_barrier do an uninterruptible wait (even moreso since it's really a spin). If a buggy callback gets stuck blocking or spinning and fails to return promptly, then you wedge any debugger thread trying to synchronize with it via utrace_barrier. If you can't even interrupt that debugger thread, then there will really be no chance to recover from the deadlock. Thanks, Roland From roland at redhat.com Wed Oct 13 07:13:59 2010 From: roland at redhat.com (Roland McGrath) Date: Wed, 13 Oct 2010 00:13:59 -0700 (PDT) Subject: gdbstub initial code, v8 && ptrace In-Reply-To: Oleg Nesterov's message of Friday, 10 September 2010 21:07:25 +0200 <20100910190725.GC27699@redhat.com> References: <20100903224047.GA8917@redhat.com> <20100906182359.GB22839@redhat.com> <20100906194229.GA27405@redhat.com> <20100906205927.GA30471@redhat.com> <20100910100948.C0254405D5@magilla.sf.frob.com> <20100910190725.GC27699@redhat.com> Message-ID: <20101013071359.A789A401B2@magilla.sf.frob.com> > But. Suppose we have to attached engines. The first engine gets > UTRACE_SIGNAL_REPORT and returns "UTRACE_STOP | UTRACE_SIGNAL_IGN". Right, that's what it would do. I see, you're saying that the report.result passed on to the next engine would appear like it had been a real signal that the previous engine decided to ignore (or whose sa_handler==SIG_IGN or default action was to ignore). Hmm. Well, it's also distinguished by having orig_ka==NULL in the callback. Any real signal has a non-null orig_ka argument. > or yes, it returns UTRACE_SIGNAL_DELIVER after gdb does "signal XX". > > Now. The second engine gets UTRACE_SIGNAL_DELIVER or UTRACE_SIGNAL_IGN, > not UTRACE_SIGNAL_REPORT. At least in the UTRACE_SIGNAL_DELIVER case, that's really the true thing for it to see. The previous engine decided to do a signal delivery (as directed by return_ka), so the next engine needs to see this to know what the prevailing state of play is now. > That is why ugdb_signal_report(UTRACE_SIGNAL_REPORT) tries to return > UTRACE_STOP | utrace_signal_action(action) to not change report->result > (passed to the next tracee) inside the reporting loop. Well, it *can* do that. If UTRACE_SIGNAL_REPORT (or anything else random) is the ultimate report.result from the whole callback loop, we treat it just like UTRACE_SIGNAL_IGN. > The worst case is UTRACE_SIGNAL_HANDLER. Single-stepping should know > about this case. This means that any engine should always return > UTRACE_resume_action | UTRACE_SIGNAL_HANDLER. I see. This is indeed the only way for any engine to know that it's getting the UTRACE_SIGNAL_HANDLER specific notification rather than some random fallout of someone else's UTRACE_REPORT request or whatnot. > > > Probably we can check orig_ka != NULL and treat orig_ka == NULL as > > > UTRACE_SIGNAL_REPORT. Hopefully this can't be confused with > > > UTRACE_SIGNAL_HANDLER. > > > > I'm not really sure what you mean here. > > If ->report_signal(orig_ka) was calles with orig_ka == NULL, then, > whatever utrace_signal_action(action) we see, originally it was > either UTRACE_SIGNAL_HANDLER or UTRACE_SIGNAL_REPORT but another engine > returned, say, UTRACE_SIGNAL_DELIVER/UTRACE_SIGNAL_IGN to deliver/stop. Right. But this is in fact just the same for either UTRACE_SIGNAL_REPORT or UTRACE_SIGNAL_HANDLER. > > > Not sure about UTRACE_SIGNAL_HOLD, but this is very unlikely race. > > > > You probably don't want to use that, but I'm not entirely sure. ptrace > > doesn't use it, and the signal interception model is pretty much the same. > > Yes, agreed. But there is one corner case. Until we generalize > utrace_stop()->ptrace_notify_stop() hook, the tracee can be reported as > stopped to gdb, but before it actually stops it can recieve a signal. I don't follow this. If we're stopping, then we don't "receive" (dequeue) any other signal until we get resumed. That should be fine from gdb's point of view. The next signal is just pending for later. The signal that we just reported was a) in fact reported to gdb and b) is still sitting in the siginfo_t on stack and the engine can examine/modify that before letting the thread resume. (The kerneldoc paragraph about @report_signal in utrace.h makes this guarantee.) Thanks, Roland From roland at redhat.com Wed Oct 13 07:23:46 2010 From: roland at redhat.com (Roland McGrath) Date: Wed, 13 Oct 2010 00:23:46 -0700 (PDT) Subject: gdbstub initial code, v7 In-Reply-To: Oleg Nesterov's message of Friday, 10 September 2010 21:20:01 +0200 <20100910192001.GA30490@redhat.com> References: <20100830185850.GA1132@redhat.com> <20100830192040.GA15431@host1.dyn.jankratochvil.net> <20100831072048.GA26362@host1.dyn.jankratochvil.net> <20100902200632.GA23692@redhat.com> <20100903064008.GA16249@host1.dyn.jankratochvil.net> <20100903230957.GC8917@redhat.com> <20100910101452.39015405D5@magilla.sf.frob.com> <20100910182903.GB27699@redhat.com> <20100910190547.85CBD405D5@magilla.sf.frob.com> <20100910192001.GA30490@redhat.com> Message-ID: <20101013072346.1F239401B2@magilla.sf.frob.com> > On 09/10, Roland McGrath wrote: > > > > > ugdb sets "please stop" flag and does utrace_control(INTERRUPT). However, > > > in unlikely case the tracee can stop before ->report_signal() reporting > > > > I don't think this is the right thing to do. When the intent is explicitly > > to interrupt, there is no reason to stop before the interruption is > > complete, i.e. report_signal. > > This means that ugdb_report_quiesce() should never return UTRACE_STOP, > and that is all. I'm not sure about this. > But what about multitracing? Suppose that "(gdb) interrupt" happens > just before, say, do_report_syscall_entry() and another engine wants > to stop. If ugdb_report_quiesce() doesn't return UTRACE_STOP, then > gdb will wait until another debugger resumes the tracee. Yes, I do think that's a problem. We want gdb to report back promptly. One possibility is to have report_quiesce notice its argument is UTRACE_EVENT(SYSCALL_ENTRY) and roll back to before the syscall. That is, it enables SYSCALL_ENTRY and SYSCALL_EXIT reporting, then its report_syscall_entry uses UTRACE_SIGNAL_ABORT, report_syscall_exit does syscall_set_return_value(-ERESTARTNOHAND, 0) and then returns UTRACE_INTERRUPT. Now, we'll reenter a UTRACE_SIGNAL_REPORT callback "before" the system call, and we can stop there without being in any sticky situation. Thanks, Roland From jistone at redhat.com Wed Oct 13 16:35:02 2010 From: jistone at redhat.com (Josh Stone) Date: Wed, 13 Oct 2010 09:35:02 -0700 Subject: Tracing with utrace, some questions In-Reply-To: <20101011214014.21979401B4@magilla.sf.frob.com> References: <87pqvik21n.fsf@karatren.ev> <20101010183503.15BD34003B@magilla.sf.frob.com> <87tykt8acz.fsf@karatren.ev> <20101011214014.21979401B4@magilla.sf.frob.com> Message-ID: <4CB5DFB6.4040502@redhat.com> On 10/11/2010 02:40 PM, Roland McGrath wrote: > In fact, the main reason UTRACE_STOP has the value zero is so that if a > careless or confused engine-writer forgets to OR in the intended value, the > result will be something that immediately obvious to be other than what the > engine probably expected, forcing you to go back and figure out the interface. Are you starved for bits? Seems like it would be better to have nothing at zero, so you could throw an honest BUG at the developer... Josh From sherilynhx35 at sina.com Wed Oct 13 19:05:46 2010 From: sherilynhx35 at sina.com (sherilynhx35 at sina.com) Date: Thu, 14 Oct 2010 03:05:46 +0800 Subject: =?GBK?B?byCzz7rP1/ejrLzbuPG1zaGj?= Message-ID: <20101013190547.07DA4330957@mail2-169.sinamail.sina.com.cn>    ??????????????????\??\???/??.??????. ???????????????.???????????!???1 3 5?3 8 0 0?3 3 6 0 ???? ? ?  ???3151?31631?muckkks08gnv3bjrz -------------- next part -------------- An HTML attachment was scrubbed... URL: From lingguohvxj at tom.com Wed Oct 13 19:49:20 2010 From: lingguohvxj at tom.com (=?gb2312?B?bGluZ2d1b2h2eGo=?=) Date: Thu, 14 Oct 2010 03:49:20 +0800 (CST) Subject: =?gb2312?B?ofK98czs08q8/mRnQGZveG1haWwuY29tbg==?= Message-ID: <4CB60D40.0001FB.14648@bjapp34> ?\???????I?????????????????????? ????????{ ?V???????????????\???? ?????????????????? }??**?????????????????? ???????? 135-5486-2829 QQ??534 580 989 -------------- next part -------------- An HTML attachment was scrubbed... URL: From jvtua.huj at live.com Thu Oct 14 02:40:31 2010 From: jvtua.huj at live.com (Adeline.Ben) Date: Thu, 14 Oct 2010 10:40:31 +0800 Subject: =?GB2312?B?xPmYhNbYyfo6tNO8vMr1tb253MDt?= Message-ID: <201010140240.o9E2eWqg013081@mx1.redhat.com> ???????????????????? ?? ?? ?? ?? ?? ?? --------------------------------------------------------------------- ???????????? 2010??10??25-26?? ???? 2010??10??28-29?? ???? ?????????????????????????????????????????????????????????? ??????????????CEO/??????????????????/??????????????/???????????????? ????????????????/??????????????????????????????????????PMO?????????? ???????????????????????????????????????????????? ??????????3,200?? / 2????????????,???????????????????????????????? ??????????????????400-8899,628 ??????????????021-5109,9475 ??????????????020-3452,0981 ?? ????rdwork at 126.com --------------------------------------------------------------------- ?????????? ??????????????????????????????????????????????????95%?????????????? ??????????????????????????????????????????????,???????????????????? ??????????????????????,???????????????????????????????????????????? ????????????????,?????????????????????????????????????????????????? ????????????????????????????????????????????????????????????,?????? ????????????????????????????????????????,?????????????????????????? ??????????????????????????????????????????????.???????????????????? ???????????????????????????????????????????????????????????????????? ??????????????????,???????????????????????????????????????????????? ?????????????????????????????????????????? --------------------------------------------------------------------- ?????????? 1.?????????????????????????????????????????????????????????????????? ?????????????? 2.???????????????????????????????????????????????? 3.?????????????????????????????????????????????? 4.?????????????????????????????????????????????????????????????????? ?????????????????? 5.???????????????????????? 6.?????????????????????????????????????????????????????????????????? ?????????????????????????????????????? 7.???????????????????????????????????????????? 8.???????????????????????????????????????????????????????????????????? ?????????????? Action Plan?????????????????????????????????????????? -------------------------------------------------------------------- ?????????? ??????????????0.5?? 1)???????????????????????? ????????????????????????????????????????1.5?? 1)???????????????????????????????????? 2)???????????????????????????? 3)???????????????????????????? *???????????????????????????????????????? *??????????????10?????????? *???????????????????????????????????????????????? *?????????????????? 4)?????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ?????????????????????? 5)???????????????????????? 6)?????????????? 7)???????????????????????????? *?????????????????????????????? *???????????????? *???????????????????????? *???????????????????????????????? *???????????????????? *???????????????????????? *???????????????????????????? *???????????????????????????? *?????????????????????????????????????? *?????????????????????????? 8?????????????????????????????????????????????? 9???????????????? ????????????????????????????????3.5?? 1)???????????????? 2)?????????? 3)?????????????????? *???????????????? *???????????????????????? *???????????????????????????? *?????????????????????????? *?????????????????????????????????????????????????? *?????????????????????????????????????????????????????????? 4)?????????????????? *???????????????????????????????? *???????????????????????????????????????????????????? *???????????????????????????????????????????? *?????????????????????????????????????????? *?????????????????? *?????????????????? *?????????????????????????????????????? *?????????????????????????????????????? *?????????????????????????????????????????????? *?????????????????????????????????????????????????????????????? *?????????????????????????????????????????????????????????????????? ???????????????????? *???????????????????????????????????????? 5)?????????????????? *?????????????????????????????????? *???????????????????????????????????????????? *???????????????????????????????????????????????????????????????????? *?????????????????????????????????????????????????????????????????? ?????????? *?????????????????????????????? 6)?????????????????? *???????????????????????? *?????????????????????? *???????????????????????? *?????????????????????????????????????? 7)?????????????????? *?????? *???????????????????????????? *??????????????5?????? *?????????????????????????????????? *?????????????????????????????????? *?????????????? *??????????????????????????QA???????? *???????????????????? *???????????????????? *??????????????????????????????????QA?????????????? *?????????????????????????????????????????????? ??????????????????????????????1.5?? 1)?????????????????????????????????????????????????? 2)?????????????????????????????????????????????????????????? 3)?????????????????? 4)?????????????????????????? 5)?????????????? 6)?????????????????????????? 7)???????????????????????????????????????????? 8)???????????????? 9)?????????????????????? 10)???????????????????????????? 11)?????????????????????? 12)???????????????????? 13)?????????????????????????? 14)???????????????????????????????? 15)?????????????????????????????????????????????????????????????????? ?????????????????? 16)?????????????????? 17)???????????????????????????????????????? 18)?????????????????? 19)???????????????????????????????????????????? ??????????????????????????????????????????????????????1.0?? 1)???????????????? 2)???????????????????????? 3)?????????????????????????????????????????????????? 4)?????????????????????????????????? 5)???????????????????????? 6)??????????????????SMART????????????????????????????PBC???? 7)??????????????????????????SMART 8)??????????????????SMART??????????????????????SMART 9)??????????????PDCA???? 10)?????????????????????????????????????????????????????????????????? 11)???????????????????? 12)?????????????????????? 13)PERT????????????GANNT 14)??????????????????????PERT?? 15)???????????????????????????????????????????????????????????? 16)???????????????????????? 17)?????????????????? 18)???????????????????????? 19)?????????????????????????????????????? ??????????????????????????????????????????????????????????2.0?? 1)???????????????????????? 2)?????????????????????? 3)???????????????????????? 4)???????????????????????? 5)?????????????????????????????????? 6)?????????????????? 7)???????????????? 8)???????????????? 9)??????????????/???????? 10)?????????????????????? 11)?????????????????????????? 12)???????????????????????? 13)?????????????????????????????????????????????????? 14)?????????????????????????????????????????????????????????? 15)???????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????? ?????????????? 16)?????????????????????????????????????????????????????????????? 17)???????? 30 ???????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? 18)???????????????????????????????????????????????????????????????????? 19)?????????????????????????????????????????????????????????????????? 20)?????????????????????????????????????????????????????????? 21)?????????????????????????????????????????????? 22)?????????????????????????????????????? ??????????????????????????????????????????????????????1.5?? 1)?????????????????????? 2)???????????????????????????? 3)?????????????????? 4)???????????????????????????????????????????? 5)???????????????????????????????????????????????? 6)???????????????????????????????????????????? 7)?????????????????????????????????????????????????????? 8)???????????????????????????????????????????????? 9)???????????????????????????????????????????????????? 10)???????????????????????????????????????????? 11)?????????????????????????????????????????????????? 12)????????????????????????????????????????????PCB?? 13)?????????????????????????????????? *???????? *???????????????????????????????? *???????????????????????????????????????????????? *???????????????????????????????????? *???????????????????? *?????????????????????????????????????????????????????????????? 14)???????????????????????????? 15)???????????????????????? 16)?????????????????????????????????????? 17)???????????????????? 18)?????????????????????????????????????? 19)???????????????????????????????? 20)???????????????????????? 21)?????????????????????????????????????? 22)?????????????????????????????????????????????????? 23)?????????????? ??????????????????????????????????????????????????????2.0?? 1)???????????????????? 2)???????????????????????? 3)???????????????????????????????????????????? 4)???????????????????????????????????? 5)???????????????? 6)???????????????????????????????? 7)???????????????????????????????? 8)???????????????????????????????????????????????? *?????????????????? *?????????????????????????????????????????? *????????????????????KPI?????????????????????????? *??????????????????BSC???????????????????? *????????????????PBC?????????????????????????? *??????????360?????????????????????????? *?????????? *???????????????????????????????? *?????????????????????????????????????? *???????????????????????????????? 9)?????????????????????????????????? *?????????????????????????????? *????????????????7???????????????????????????????????????????????? ?????????????????????????????????????????????????????????????? *?????????????????????????????????????????????????????????????????? ???????????????????????????????? *?????????????????????????????????????????? *????????????????????????????????????????????QA???????????????????? ?????????????????? 10)???????????????????????????????????????? *???????????????????? *???????????????????????????????????????? *?????????????????????????????????????????? *???????????????????????????????????????????? *?????????????????????????????????????????????????????????????????? ?????????????????????????? *???????????????????????????????????? *???????????????????????????????????? *???????????????????????????????????????????? *?????????????????????????????????????????????????????? *?????????????????????????????????????????????????????????????????? ???????????????????????? *?????????????????????????????? *???????????????????????????????????????????????????? 11)?????????? ??????????????????????????????????????0.5?? 1)?????????????????? 2)?????????????? 3)?????????????????????????????????? 4)?????????????????????? 5)?????????????????????????????????????????? --------------------------------------------------------------------- ?????????? ??????(Giles) -???????? ???????? 10?????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ????????????IPD????????????ITS&P????,????IPD???????????????????????? ????????????????????????????????IPD??????????????,?????????????????? ???????????????? ???????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ??????????????,?????????????????????????????????????????????????????? ???????????????????? ???????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ??????????????????????10???????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????? --------------------????????????????????????----------------------------- ??????????(FAX:020-62351993 021-51062638) ??????????????????????????????????????5???????????????????????? ?????????????????????????????????????????????? ??????????____________________________________ ????????????____________ ??????????______________ ??????????_____________ ??????????____________ ??????????___________ ?? ??????????_____________ ?? ?? ?? ????______________ ??????????_____________ ??????????____________ ?? ?? ????______________ ??????????_____________ ??????????____________ ?? ?? ????______________ ??????????_____________ ??????????____________ ??????????????????????????????????????????????????????????,???????????? ?????????????????????????? ????????????????/???? ????????????????????????????????????????______?? ??????????????????????????????????????????2010??___??___???????? ____?? ????????????????____ ??????????????____ ?????????????? ????????????????????????????__________________________________________ ______________________________________________________________________ ______________________________________________________________________ From marketing at masterplugin.com.br Tue Oct 12 19:50:46 2010 From: marketing at masterplugin.com.br (Masterplugin) Date: Tue, 12 Oct 2010 15:50:46 -0400 Subject: =?UTF-8?B?Q2FuZXRhIGVzcGnDoyBmaWxtYSBhdMOpIDkgaG9yYXM=?= Message-ID: <5cb0d60644a0b5b64abcb7714910a28e@189.1.164.117> An HTML attachment was scrubbed... URL: From but at elzd.com Thu Oct 14 05:06:56 2010 From: but at elzd.com (=?GB2312?B?x+vXqsjLysI=?=) Date: Thu, 14 Oct 2010 13:06:56 +0800 Subject: =?GB2312?B?QjF1dHJhY2UtZGV2ZWzP+srbvqvTorXEvKTA+A==?= Message-ID: <201010140506.o9E56pfY024153@mx1.redhat.com> utrace-devel????????2?????????? ???????????????????????????????????????????????????????????????????????????? ??????????2010??10??23-24?? ???? ??????????2010??10??30-31?? ???? ??????????2010??11??6-7?? ???? ??????????2010??11??13-14?? ???? ??????????2010??11??20-21?? ???? ??????????2010??11??27-28?? ???? ???????????????????????????????????????????????????????????????????? ??????????2470??/??????2???????????????????????????????? ??????????020-80560638??020-85917945??????????????????????????????????chinammc2010 at 126.com?????? ====================================================================================== ??????????Judge??????????????????????????????????????????????????Harvard???????????????????? Stanford??????????????.????judge??????????????????????????????????????judge???????????????? ?????????????????????????????????????????????????? ?D?D?D?D?D?D???????????????? 1?????????????????????????????????????????????? 2?????????????????????????????????????????????????????????? 3?????????????????????????????????????????? 4?????????????????????????????????????????????? 5?????????????????????????????????????????????????????? 6?????????????????????????????????????????? 7?????????????????????????????????????????????????????? 8?????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ???????????? ??????????????????????10?????? 1???????????????????????????????????? 2?????????????????????????????? 3???????????????????????????????? 4?????????????????????????????? 5???????????????????????????????? 6???????????????????????????????? 7?????????????????????????????? 8?????????????????????????????????????? 9?????????????????????????????????? 10???????????????????????????????? ??????????????????9?????????? 1?????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????? 2???????????????????????????????????? ?????????????????????????????????????? ?????????????????????????????????? 3?????????????????????????? ???????????????????????????????????? 4???????????????????????????? ???????????????????????????????????????????? 5?????????????????????????????????????? ???????????????????????????????????? 6?????????????????????????? ???????????????????????????????????????? 7?????????????????????????????? ?????????????????????????? 8?????????????????????????????????? ?????????????????????????????????????? 9???????????????????????????????????????????? ?????????????????????????????????? ??????????????????????????????????????????? A?????????????????????????? ???????????????????????????????????????? ???????????????????????????????? ?????????????????? B???????????????????????????? 1???????????????????????????? 2?????????????????????????????????? 3???????????????????????????????????? 4???????????????????????????????????? 5???????????????????????????????? 6?????????????????????????????? 7???????????????????????????????????????????????? C???????????????????????? ???????????????????????????????????? ?????????????????????????????????????? ??????????????????????????????! ???????????????????????????? ???????????????????????????? ???????????????????????????????? ??????3???????? ????????????????6?????? ???????????????????????????????????? 1???????????????????? 2???????????????????? 3?????????????????????????? 4?????????????????????? ?????????????????? ??????????????????????9???????? ??????????????????????????5???????? ??????????????????????4???????? ????????????,????????????3??????? ??????????,??????????4??????? ?????????????????????????????????????? ?????????????????????????????? ??????????????????????7?????????????????? ??????????????????????4???????????????????????????? ??????????????????????????3???? ?????????????????????????????????? ???????????????????? 1???????????????? ???????????????????????????????????? ????????????????????4???????? ????????????????6?????? ???????????????????????????????? 2???????????????????? ?????????????????????????????????????????????? ?????????????????????????????????????????????? ???????????????????????????????? ??????????????6?????????? ?????????????? ???????????????????????? ???????????????????????? ???????????????????????? 1???????????????????????????????????? 2???????????????????????????????????????? 3?????????????????????? ???????????????????????????????????????????????????????????????????????????? ?????????????????? ???????????????????????????? ?????????????????????????????????? ?????????????????????????????????? ???????????????????????????????????????? ????????.????????.????????EMBA???????????? 2000??????????????????????????????????????????,???????????????????????????????? ??????????????????????????,??????????????????100?????????????????????????????? ????????????????????????,??????????????????,?????????????????????????????????? ???????????????????????????????????????????????????????????? ---------------------------------------------------------------------------- ??????????2??????????????????????????????????020-62351156?? ??????????????_______________________________________________________ ???????????????? ?????? ?????? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________????????:_________??????????_________?? ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ??????????????????????????????1????????2????????3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From ecy at imgd.com Thu Oct 14 07:35:10 2010 From: ecy at imgd.com (=?GB2312?B?xeDRtQ==?=) Date: Thu, 14 Oct 2010 15:35:10 +0800 Subject: =?GB2312?B?dXRyYWNlLWRldmVs16jStcPYyum8vMTczOHJ/Q==?= Message-ID: <201010140735.o9E7Z4OY030690@mx1.redhat.com> utrace-devel???????????????????????????????? ??????2010??10??16-17?? ?????????? ????: 2010??10??23-24?? ?????????? ??????2010??10??30-31?? ?????????? ??????????2500/???????????????????????????????????? ?????????????????????????????????????????????????????????????? ??????????020-80560638??020-85917945 ????????????????????????????chinammc2010 at 126.com?????? ======================================================================================== ???????????????????? 1.?????????????????????????????????????????????????????????????????????? 2.???????????????????????????????????????? 3.???????????????????????????????????????????? 4.?????????????????????????????????????????????????????????????? 5.?????????????????????????????????????????????? 6.?????????????????????????? 7.?????????????????????????????????????????? 8.???????????????????????????????????????????????????????? 9.???????????????????????????????????????????? 10.???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????? ?????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????? ?????????? ???????????????????????????????????????????? ?????????????????????????????????????????????? ???????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????? =========================================================================================== ????????: ???????? ????/?????????????? 1.????/???????? 2.????????/???????????????? 3.????????/?????????????????????????? 4.????????/???????????????????????? 5.???????????????????????D?D?????????????????? 6.???????????????????????????? 7.?????????????????????????????????????????? 8.????/?????????????????? 9.???????????????????????????????????????????? ???????? ????????/?????????????? 1.????/?????????????????D?D????????????????/????/???????? 2.?????????????????????? 3.?????????????????????????????????????????????????? 4.????????????????????PDP??????NLP???? 5.????????????????????????????5W1H?????????? 6.?????????????????????????? 7.???????????????? 8.???????????????????????????????????????????????????????????????? ???????? ????????5S???? 1.5S?????? 2.???????????????????????? 3.???????????????????????? 4.???????????????????????? 5.???????????????????????? 6.???????????????????????????? ???????????????? 1.??????????5?????? 2.???????????????????????????? 3.?????????????????? 4.???????????????????????????????? 5.???????????????????????????????????????????????????????? 6.?????????????????????????????????????????????? 7.?????????????????????????? ?????????????????????????? 1.???????????????????????????? 2.PDCA?????????????????????????? 3.????SMAC???????????????????? 4.??????????/????/?????????????????????? 5.???????????????????????????????????????????????????????? ?????????????????????????????????? 1.?????????????? 2.?????????????? 3.?????????????????????????????????? 4.?????????????????? 5.????????????????????12?????? 6.?????????????????? 7.???????? 8.???????????????????????????????? ???????????????? 1.???????????????? 2.?????????????????? 3.?????????????????? 4.?????????????????? 5.?????????????????? 6.?????????????????? 7.?????????????????? ?????????????????????????????? 1.???????? 2.?????????? 3.?????????????????? ???????????????????? 1.?????????????????????????????? 2.?????????????? ???????????????????????????????????????????????????????????????? ??????????????????????????????/????/?????????????????????????????????????? 3.?????????????????????????????? ?????????????????????????????????????????????? ========================================================================================== ???????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????5????????????500?????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????????????????????TTT???????????????? ??????????????????????????/???????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????????????????????????????????????????TCL?? ???????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????? =========================================================================================== ??????????/????????????????????????????????????????????????????020-62351156?? ?? ?? ?? ?? ?? ????_______________________________________________________ ?? ?? ?? ???? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________ ?? ?? ?? ??:_________?? ?? ?? ????_________?? ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ???????????????????????????? ??1?????? ??2?????? ??3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From evident at hoffys.org Thu Oct 14 14:52:45 2010 From: evident at hoffys.org (Coby Deuink) Date: Thu, 14 Oct 2010 16:52:45 +0200 Subject: e the various games were pla Message-ID: <79122527441000@hoffys.org> A non-text attachment was scrubbed... Name: surceasing.png Type: image/png Size: 20932 bytes Desc: not available URL: From roland at redhat.com Thu Oct 14 23:09:08 2010 From: roland at redhat.com (Roland McGrath) Date: Thu, 14 Oct 2010 16:09:08 -0700 (PDT) Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: Oleg Nesterov's message of Sunday, 26 September 2010 17:48:39 +0200 <20100926154839.GA20803@redhat.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> Message-ID: <20101014230908.9252840096@magilla.sf.frob.com> > The 1st patch I sent initially: > > --- kstub/kernel/utrace.c~10_utrace_reset_should_clear_ss 2010-09-20 03:55:12.000000000 +0200 > +++ kstub/kernel/utrace.c 2010-09-20 21:33:47.000000000 +0200 > @@ -709,6 +709,7 @@ static bool utrace_reset(struct task_str > */ > utrace->resume = UTRACE_RESUME; > utrace->signal_handler = 0; > + user_disable_single_step(task); > } > > /* > > It clears TIF_SINGLESTEP when the last engine detaches. This we didn't want because utrace_reset can be called when the tracee is not stopped, and it's not safe to call user_*_step then (with the one caveat that the SIGKILL race is OK). > The 2nd one which changes utrace_control(DETACH), > > @@ -1139,7 +1139,9 @@ int utrace_control(struct task_struct *t > target->utrace_flags &= ~ENGINE_STOP; > mark_engine_detached(engine); > reset = reset || utrace_do_stop(target, utrace); > - if (!reset) { > + if (reset) { > + user_disable_single_step(target); > + } else { > /* > * As in utrace_set_events(), this barrier ensures > * that our engine->flags changes have hit before we > > It doesn't cover the case when the TIF_SINGLESTEP tracee detaches > itself, but a) currently the are no such engines, and b) it looks > more clean. If we're trying to meet the advertised API--how it's documented now is the only reasonable thing if we are actually fixing things properly at all--we do need to cover the case where the only engine to have requested single-step earlier then later returns UTRACE_DETACH from a callback. That is, if that engine could actually know that the tracee never reached user mode between its use of UTRACE_SINGLESTEP and its later UTRACE_DETACH. > However, I am starting to think that if you prefer this change we > have a better option. Instead of duplicating UTRACE_RESUME logic, > perhaps the patch below makes more sense? Hmm, that does seem like it might be pretty reasonable. If your engine had ever permitted the tracee to get back to user mode after requesting UTRACE_*STEP, then it's just desserts to cause that SIGTRAP regardless of whether other engines might have kept it stopped in actuality. But, there might be plausible corners where an engine really could know reliably (without outside knowledge of what other engines might be doing) that the tracee can't really have been back to user mode yet. For example, if it checked signal_pending(tracee) before it used UTRACE_*STEP, then it could know for sure that its report_signal callback will have been called before it ever got to user mode, so if that callback returns UTRACE_DETACH, it better not be left with stepping enabled. In that particular case, it shouldn't be a problem, since after its report_signal we will always hit finish_resume_report later. But we should think about if there are any holes of a similar nature. > Please tell me which fix you prefer? Or just commit the fix you > like more. I'm only going to merge a specific commit of yours that you have tested. Thanks, Roland From roland at redhat.com Thu Oct 14 23:46:18 2010 From: roland at redhat.com (Roland McGrath) Date: Thu, 14 Oct 2010 16:46:18 -0700 (PDT) Subject: utrace && unwanted traps In-Reply-To: Oleg Nesterov's message of Sunday, 26 September 2010 18:01:03 +0200 <20100926160103.GB20803@redhat.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926160103.GB20803@redhat.com> Message-ID: <20101014234618.5088940096@magilla.sf.frob.com> > In short: I no longer understand why utrace->resume can be UTRACE_*STEP > when the tracee is stopped, and in fact I think this is not right. I think we didn't have that originally. The rationale that I remember is the idea that you should be able to implement a debugger interface feature like PTRACE_SINGLESTEP without noticeably more overhead than it had in pre-utrace ptrace. That is, in vanilla ptrace, the tracer thread calls user_enable_single_step itself and then just lets the tracee resume directly to user mode. We wanted to avoid always having an additional trip through tracehook_notify_resume and the utrace reporting loop and then back through the return-to-user assembly path a second time, between the tracee waking up and actually going to user mode. > For example. Consider two engines, E1 and E2. To simplify the discussion > suppose that both engines have engine->data->resume and ->report_quiesce() > just returns ->resume. So, if the debugger wants, say, single-step, it > does > > engine->data->resume = UTRACE_SINGLESTEP; > utrace_control(UTRACE_SINGLESTEP); > > Actually, any engine should do something like this. Right. > Now suppose that E1 wants UTRACE_SINGLESTEP, E2 asks for UTRACE_STOP. > In this case utrace_resume() results in utrace_stop() which sets > utrace->resume = UTRACE_SINGLESTEP before sleeping. > > First of all - why? Yes, the theory is that we have another reporting > loop after wake_up, but utrace->resume = UTRACE_REPORT is enough, E1 > should always acquire UTRACE_SINGLESTEP if needed or it is buggy. If E2 uses UTRACE_RESUME rather than UTRACE_REPORT, nobody actually cared about another callback before user mode. So indeed the theory is that this lets E1 get its single-step without the overhead of a reporting loop that serves no other purpose than that. But you are right that any engine is buggy if it doesn't dtrt in such a reporting loop, since some other engine might have used UTRACE_REPORT. > But more importantly, this doesn't look right or I missed something. > Suppose that, before E2 resumes the tracee, E1 does utrace_control(STOP) > which immediately succeeds and allows E1 to play with the stopped tracee. > Again, to simplify the discussion, suppose that E2 does UTRACE_RESUME > and nothing more after that. > > Now. E1 wants to resume the tracee too and it does > > engine->data->resume = UTRACE_RESUME; > utrace_control(UTRACE_RESUME); > > utrace_control(RESUME) correctly clears TIF_SINGLESTEP, but it doesn't > change utrace->resume. This means utrace_resume() doesn't do the > reporting loop, it just calls user_enable_single_step() and returns > to user-mode. Yes, that sounds wrong. > So. Could you explain why utrace_stop() should ever keep UTRACE_STEP > in utrace->resume? finish_report() does the same but this looks fine. I cannot. > Also. I am not sure utrace_control(UTRACE_STEP) should always set > utrace->resume = UTRACE_STEP. If the tracee is stopped but there > is another ENGINE_STOP engine (iow, the tracee won't be resumed > right now) we have the same problem. Right. Said another way, any time an engine that previously used UTRACE_*STEP now uses UTRACE_RESUME, we must degrade utrace->resume back to UTRACE_REPORT at most. Since we don't keep track of which engine it was that put UTRACE_*STEP into utrace->resume before, we'd have to just always degrade it any time anybody uses UTRACE_RESUME. That has almost the whole effect of punting utrace->resume back to just a utrace->report flag. But that's how it used to be, and then we changed it. So it merits digging up our old discussion threads that led to doing that and see what all we had in mind then. > Off-topic, > > #define UTRACE_RESUME_BITS (ilog2(UTRACE_RESUME_MAX) + 1) > > why UTRACE_RESUME_MAX? it should be (ilog2(UTRACE_RESUME_MAX - 1) + 1), no? Yes, I think you're right. Thanks, Roland From erb at iulb.com Fri Oct 15 03:09:09 2010 From: erb at iulb.com (=?GB2312?B?16rQ6MfzyMvUsQ==?=) Date: Fri, 15 Oct 2010 11:09:09 +0800 Subject: =?GB2312?B?dXRyYWNlLWRldmVssta0orncwO3T67mks6fO78HPxeTLzQ==?= Message-ID: <201010150309.o9F38qS5015273@mx1.redhat.com> utrace-devel????????????? ?????2010?10?25-26? ?? ?????2010?11?26-27? ?? ?????2010?12?10-11? ?? ?????????????????????????????????????? ?????2800?/????????????????????? ?????020-80560638?020-85917945?????????????????chinammc2010 at 126.com??? -------------------------------------------------------------------------------------- ??????????????????????????????????????????????? ????????????????????????????????????????????????? ???????????????? ??????????? ????????? ??????????? ?????????? ???????????? ????????? ????????? ???????? ????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????? --------------------------------------------------------------------------------------------- ?????????????????????????1986????Gerber?????????Michigan State University (??????) ???????????,?????Heinz(??)????? ??????????????????????????????????????????????? ????2000???,????????????????????????,???????500????? ????????,??????????????????????????????????????? ???????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ???????????ABB?????????????????????,?????????,??,? ??????????,?????,???????? ---------------------------------------------------------------------------- ??????????????????? ????????????? ??????????????? ???????????????-KPI? ???????? ?????????????? ????????????????? ????????????? ?????????????????????????? ??????????????? ?????KPI??? ???????????? ?????????? ????? ?????????? ????????? ??????????? ???????? ??????????? ??????? ????????? ??????????????????? ????????????? ??????????? ???????? ?????KPI????? ????????? ??????? ??????????? ??????????? ?????????? ????????????????????? ????????????????? ??????????????? ???KPI?????? ?????????? ??????? ?????????? ??????? ???????? ??????????? ??????????????? ????????????????? ?????KPI??? ???????????? ??????? ????????????? ????????????? ????????? ??????????? ?????KPI????? ??KPI??? ?????????? ??????????? ?????????? ?????????????? ????JIT? ???????????????????? ??????????????????? ???????????? ?????KPI?????? ?????????????? VMI??????? VMI????? "?????? " "?????? ????????????? "?????????????? ?????????KPI????? ???????KPI??? ????KPI?????? ?????? ???????????? ?????????????? ???????? ?????????????????? "?????????????? ????????KPI?????? ??????????? ?????????? ????????? ??????? ???????? ?????????? ??????????? ????????? ?????????????? ????????? ?????????????? ?????? ????? ??????????? ???????????? ?????????? ???????? ???????????????? "?????????????????? " ??????????????? ????????? ????????? ???????? ????????? ?????????? ??????????? ??????? ????????? ?????????????? ???????????????? ??????????????? ??????????? ???????? ?????????????? ?????????????? ??????? ??????????? ??????? ??????????? ???????? ??????????? ??????????????? ????? ??????????????5S??? ??????????? ???????? ???????????????????? ???????????????? ??????????? ??????? ???? ?????? ????? ????? ????? ????????? ???????????????? ?????????????? ??????? ????? ?????????? ????????? ???????? ??? ??????? ???? ???? ?????????????? ?????KPI? ????????? ??????? ?????????? ??????? ?????????? ??????? ??????????? ????:???????? ???????????????????? ???????? MRP II?DRP?ERP ?????? ?????? ??????????? ???????? ??????????? ????? ????????? RFID? ?????RFID? GPS?POS ?????????????????????? ?????RFID???????? ERP???????????????? ------------------------------------------------------------------------------------ ????????????????????????020-62351156? ? ? ? ? ? ??_______________________________________________________ ? ? ? ????? ??? ????______________??:________________??:________________ ???______________ ? ? ? ?:_________? ? ? ??_________? ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ?????????????? ?1??? ?2??? ?3??? ==================================================================================== ??:????????????????????,???????020-80560638???! From oleg at redhat.com Fri Oct 15 13:52:58 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 15 Oct 2010 15:52:58 +0200 Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: <20101013065538.63094401B2@magilla.sf.frob.com> References: <20100818172704.GA2230@redhat.com> <20101013065538.63094401B2@magilla.sf.frob.com> Message-ID: <20101015135258.GA4534@redhat.com> On 10/12, Roland McGrath wrote: > > > If engine is detached (has utrace_detached_ops), utrace_barrier(engine) > > spins until engine->ops becomes NULL. This is just wrong. > > Yes, this happens because get_utrace_lock returns -ERESTARTSYS and > utrace_barrier checks for this and loops. I agree these long-spin > scenarios would be wrong. > > The reason it tries to wait for "fully detached" state is that after > utrace_control(task,engine,UTRACE_DETACH), @task could still be in the > middle of a callback for @engine. Yes. But, with this patch, in this case utrace_barrier()->get_utrace_lock(attached => false) returns success and then we check utrace->reporting == engine. This patch only makes a difference if ops == utrace_detached_ops, Before this patch spin until ->ops goes away After this patch spin until ->ops goes away OR ->reporting != engine (Hmm. Probably utrace->reap = T case needs more attention, utrace_maybe_reap() doesn't set utrace->reporting). > > Also, it is not clear why utrace_barrier() needs utrace->lock, > > except to ensure it is safe to dereference target/utrace. > > Well, wouldn't that be reason enough? The comment in utrace_barrier > talks about needing the lock. This corresponds to the comment in the > UTRACE_DETACH case of finish_callback_report. Yes agreed. Honestly, I can't even recall what I meant. > > Note: we should also reconsider() utrace_barrier()->signal_pending() check. > > IMHO it is badly wrong to have utrace_barrier do an uninterruptible wait > (even moreso since it's really a spin). If a buggy callback gets stuck > blocking or spinning and fails to return promptly, then you wedge any > debugger thread trying to synchronize with it via utrace_barrier. If > you can't even interrupt that debugger thread, then there will really be > no chance to recover from the deadlock. Completely agreed. But, unfortunately, this signal_pending() check assumes the caller can always handle this ERESTARTSYS. But this is not true, one example is the exiting debugger doing exit_ptrace(). Oleg. From oleg at redhat.com Fri Oct 15 13:53:27 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 15 Oct 2010 15:53:27 +0200 Subject: gdbstub initial code, v8 && ptrace In-Reply-To: <20101013071359.A789A401B2@magilla.sf.frob.com> References: <20100903224047.GA8917@redhat.com> <20100906182359.GB22839@redhat.com> <20100906194229.GA27405@redhat.com> <20100906205927.GA30471@redhat.com> <20100910100948.C0254405D5@magilla.sf.frob.com> <20100910190725.GC27699@redhat.com> <20101013071359.A789A401B2@magilla.sf.frob.com> Message-ID: <20101015135327.GB4534@redhat.com> On 10/13, Roland McGrath wrote: > > > But. Suppose we have to attached engines. The first engine gets > > UTRACE_SIGNAL_REPORT and returns "UTRACE_STOP | UTRACE_SIGNAL_IGN". > > Right, that's what it would do. I see, you're saying that the > report.result passed on to the next engine would appear like it had > been a real signal that the previous engine decided to ignore (or > whose sa_handler==SIG_IGN or default action was to ignore). Hmm. > > Well, it's also distinguished by having orig_ka==NULL in the callback. > Any real signal has a non-null orig_ka argument. Yes, this is what ugdb does. ptrace doesn't, I didn't realize this problem when I was writing that code. > > or yes, it returns UTRACE_SIGNAL_DELIVER after gdb does "signal XX". > > > > Now. The second engine gets UTRACE_SIGNAL_DELIVER or UTRACE_SIGNAL_IGN, > > not UTRACE_SIGNAL_REPORT. > > At least in the UTRACE_SIGNAL_DELIVER case, that's really the true > thing for it to see. The previous engine decided to do a signal > delivery (as directed by return_ka), so the next engine needs to see > this to know what the prevailing state of play is now. Agreed. Currently ugdb doesn't report a signal injected by another engine. > > > I'm not really sure what you mean here. > > > > If ->report_signal(orig_ka) was calles with orig_ka == NULL, then, > > whatever utrace_signal_action(action) we see, originally it was > > either UTRACE_SIGNAL_HANDLER or UTRACE_SIGNAL_REPORT but another engine > > returned, say, UTRACE_SIGNAL_DELIVER/UTRACE_SIGNAL_IGN to deliver/stop. > > Right. But this is in fact just the same for either > UTRACE_SIGNAL_REPORT or UTRACE_SIGNAL_HANDLER. Now I am not sure what you mean... Yes, if the callback returns UTRACE_SIGNAL_REPORT then the next callback will see "orig_ka == NULL" too, sure. But I guess you meant something else. > > > > Not sure about UTRACE_SIGNAL_HOLD, but this is very unlikely race. > > > > > > You probably don't want to use that, but I'm not entirely sure. ptrace > > > doesn't use it, and the signal interception model is pretty much the same. > > > > Yes, agreed. But there is one corner case. Until we generalize > > utrace_stop()->ptrace_notify_stop() hook, the tracee can be reported as > > stopped to gdb, but before it actually stops it can recieve a signal. > > I don't follow this. If we're stopping, then we don't "receive" > (dequeue) any other signal until we get resumed. That should be fine > from gdb's point of view. The next signal is just pending for later. Hmm. Yes. If a callback ever returned UTRACE_STOP, utrace_get_signal() should notice utrace->resume <= UTRACE_REPORT. OK, so ugdb doesn't need this hack. Thanks. Now I am wondering how I managed to test this UTRACE_SIGNAL_HOLD code. I recall, initially it returned "UTRACE_STOP | UTRACE_SIGNAL_HOLD", then the testing showed it doesn't work and I added UTRACE_SIGNAL_REPORT. Probably I added some hacks to simulate the problem which, as you showed, doesn't exist. Oleg. From oleg at redhat.com Fri Oct 15 14:28:15 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 15 Oct 2010 16:28:15 +0200 Subject: gdbstub initial code, v7 In-Reply-To: <20101013072346.1F239401B2@magilla.sf.frob.com> References: <20100830192040.GA15431@host1.dyn.jankratochvil.net> <20100831072048.GA26362@host1.dyn.jankratochvil.net> <20100902200632.GA23692@redhat.com> <20100903064008.GA16249@host1.dyn.jankratochvil.net> <20100903230957.GC8917@redhat.com> <20100910101452.39015405D5@magilla.sf.frob.com> <20100910182903.GB27699@redhat.com> <20100910190547.85CBD405D5@magilla.sf.frob.com> <20100910192001.GA30490@redhat.com> <20101013072346.1F239401B2@magilla.sf.frob.com> Message-ID: <20101015142815.GA6026@redhat.com> On 10/13, Roland McGrath wrote: > > > On 09/10, Roland McGrath wrote: > > > > > > > ugdb sets "please stop" flag and does utrace_control(INTERRUPT). However, > > > > in unlikely case the tracee can stop before ->report_signal() reporting > > > > > > I don't think this is the right thing to do. When the intent is explicitly > > > to interrupt, there is no reason to stop before the interruption is > > > complete, i.e. report_signal. > > > > This means that ugdb_report_quiesce() should never return UTRACE_STOP, > > and that is all. > > I'm not sure about this. Ignoring the problems below, why? > > But what about multitracing? Suppose that "(gdb) interrupt" happens > > just before, say, do_report_syscall_entry() and another engine wants > > to stop. If ugdb_report_quiesce() doesn't return UTRACE_STOP, then > > gdb will wait until another debugger resumes the tracee. > > Yes, I do think that's a problem. We want gdb to report back promptly. > One possibility is to have report_quiesce notice its argument is > UTRACE_EVENT(SYSCALL_ENTRY) and roll back to before the syscall. > That is, it enables SYSCALL_ENTRY and SYSCALL_EXIT reporting, then > its report_syscall_entry uses UTRACE_SIGNAL_ABORT, report_syscall_exit > does syscall_set_return_value(-ERESTARTNOHAND, 0) and then returns > UTRACE_INTERRUPT. Now, we'll reenter a UTRACE_SIGNAL_REPORT callback > "before" the system call, and we can stop there without being in any > sticky situation. Well, but this doesn't look friendly to other engines... And at first glance this looks a bit too hairy. And, this doesn't cover another case: gdb asks to stop the tracee when it is already stopped by another engine and sleeps in utrace_resume() path. So, I think ugdb should be changed so that "signal SIG" always works (without reporing this signal) even when the stopped tracee doesn't have the signal context. As for $_siginfo (qXfer:siginfo:read::), I do not know what ugdb should do. Probably it can just report the all-zeroes siginfo or report si_signo = SIGSTOP. Oleg. From qcn at yujo.com Sat Oct 16 03:03:14 2010 From: qcn at yujo.com (=?GB2312?B?x+vXqs/gudjIy9Sx?=) Date: Sat, 16 Oct 2010 11:03:14 +0800 Subject: =?GB2312?B?QjF1dHJhY2UtZGV2ZWzP+srbvqvTorXEvKTA+A==?= Message-ID: <201010160303.o9G33863011661@mx1.redhat.com> utrace-devel????????2?????????? ???????????????????????????????????????????????????????????????????????????? ??????????2010??10??23-24?? ???? ??????????2010??10??30-31?? ???? ??????????2010??11??6-7?? ???? ??????????2010??11??13-14?? ???? ??????????2010??11??20-21?? ???? ??????????2010??11??27-28?? ???? ???????????????????????????????????????????????????????????????????? ??????????2470??/??????2???????????????????????????????? ??????????020-80560638??020-85917945??????????????????????????????????chinammc2010 at 126.com?????? ====================================================================================== ??????????Judge??????????????????????????????????????????????????Harvard???????????????????? Stanford??????????????.????judge??????????????????????????????????????judge???????????????? ?????????????????????????????????????????????????? ?D?D?D?D?D?D???????????????? 1?????????????????????????????????????????????? 2?????????????????????????????????????????????????????????? 3?????????????????????????????????????????? 4?????????????????????????????????????????????? 5?????????????????????????????????????????????????????? 6?????????????????????????????????????????? 7?????????????????????????????????????????????????????? 8?????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ???????????? ??????????????????????10?????? 1???????????????????????????????????? 2?????????????????????????????? 3???????????????????????????????? 4?????????????????????????????? 5???????????????????????????????? 6???????????????????????????????? 7?????????????????????????????? 8?????????????????????????????????????? 9?????????????????????????????????? 10???????????????????????????????? ??????????????????9?????????? 1?????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????? 2???????????????????????????????????? ?????????????????????????????????????? ?????????????????????????????????? 3?????????????????????????? ???????????????????????????????????? 4???????????????????????????? ???????????????????????????????????????????? 5?????????????????????????????????????? ???????????????????????????????????? 6?????????????????????????? ???????????????????????????????????????? 7?????????????????????????????? ?????????????????????????? 8?????????????????????????????????? ?????????????????????????????????????? 9???????????????????????????????????????????? ?????????????????????????????????? ??????????????????????????????????????????? A?????????????????????????? ???????????????????????????????????????? ???????????????????????????????? ?????????????????? B???????????????????????????? 1???????????????????????????? 2?????????????????????????????????? 3???????????????????????????????????? 4???????????????????????????????????? 5???????????????????????????????? 6?????????????????????????????? 7???????????????????????????????????????????????? C???????????????????????? ???????????????????????????????????? ?????????????????????????????????????? ??????????????????????????????! ???????????????????????????? ???????????????????????????? ???????????????????????????????? ??????3???????? ????????????????6?????? ???????????????????????????????????? 1???????????????????? 2???????????????????? 3?????????????????????????? 4?????????????????????? ?????????????????? ??????????????????????9???????? ??????????????????????????5???????? ??????????????????????4???????? ????????????,????????????3??????? ??????????,??????????4??????? ?????????????????????????????????????? ?????????????????????????????? ??????????????????????7?????????????????? ??????????????????????4???????????????????????????? ??????????????????????????3???? ?????????????????????????????????? ???????????????????? 1???????????????? ???????????????????????????????????? ????????????????????4???????? ????????????????6?????? ???????????????????????????????? 2???????????????????? ?????????????????????????????????????????????? ?????????????????????????????????????????????? ???????????????????????????????? ??????????????6?????????? ?????????????? ???????????????????????? ???????????????????????? ???????????????????????? 1???????????????????????????????????? 2???????????????????????????????????????? 3?????????????????????? ???????????????????????????????????????????????????????????????????????????? ?????????????????? ???????????????????????????? ?????????????????????????????????? ?????????????????????????????????? ???????????????????????????????????????? ????????.????????.????????EMBA???????????? 2000??????????????????????????????????????????,???????????????????????????????? ??????????????????????????,??????????????????100?????????????????????????????? ????????????????????????,??????????????????,?????????????????????????????????? ???????????????????????????????????????????????????????????? ---------------------------------------------------------------------------- ??????????2??????????????????????????????????020-62351156?? ??????????????_______________________________________________________ ???????????????? ?????? ?????? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________????????:_________??????????_________?? ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ????????___________??????????____________??????????_____________ ??????????????????????????????1????????2????????3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From premier at ultraemail.com.br Fri Oct 15 20:43:26 2010 From: premier at ultraemail.com.br (Premier Training) Date: Fri, 15 Oct 2010 16:43:26 -0400 Subject: =?UTF-8?B?RklOQU7Dh0FTIFBFU1NPQUlTIOKAkyBDT01PIEFETUlOSVNUUkFSIEJFTSBPIFNFVSBESU5IRUlSTw==?= Message-ID: <6f9c366e258c418a6f5f19148363f557@189.1.164.117> An HTML attachment was scrubbed... URL: From triphosphate at nexstar.jp Sat Oct 16 07:31:38 2010 From: triphosphate at nexstar.jp (Schwien Fellezs) Date: Sat, 16 Oct 2010 09:31:38 +0200 Subject: Th something sharper than dried peas?" "I think h Message-ID: <4A0A9687578201A1@nexstar.jp> A non-text attachment was scrubbed... Name: electrolyzes.png Type: image/png Size: 21170 bytes Desc: not available URL: From info at voidcreations.org Sat Oct 16 14:36:41 2010 From: info at voidcreations.org (Void Creations) Date: Sat, 16 Oct 2010 14:36:41 +0000 Subject: ESTE FIM-DE-SEMANA ! LISBON ROCK FEST - Sexta/Sabado 15/16 Outubro @ Santiago Alquimista Message-ID: <8afde81628890e849482cca820917ed6@voidcreationsnewsletter.com> Se n?o visualizares esta p?gina correctamente, clica aqui Adiciona-nos ? tua safe-list, para garantir que recebes sempre a info dos nossos eventos. **** **Apresenta:** ** ** Lisboa vai receber o melhor festival de rock do pa?s. A 1? edi??o do Lisbon Rock Fest vai estar no Santiago Alquimista, nos pr?ximos dias 15 e 16 de Outubro. Num fim-de-semana que se vai fazer de verdadeiro rock n'roll a Costa do Castelo vai estremecer com atrac??es t?o bomb?sticas quanto o garage rock dos lend?rios The Fuzztones - que celebram o seu 30? anivers?rio de carreira nesta digress?o - os animalescos Los Peyotes e as melhores bandas nacionais, entre as quais The Texabilly Rockets, The Poppers, Tiguana Bibles e at? os brasileiros The Black Needles. Para al?m dos concertos, o Lisbon Rock Fest traz tamb?m os dj's mais conceituados para o after-party, criando um ambiente do qual Lisboa n?o se vai esquecer t?o cedo. A comandar os pratos estar?o Jo?o Ribas (ex-Censurados, Tara Perdida), Rui Maia (X-Wife), Nuno Calado (No DJ's, Antena 3), Jo?o Pedro Almenda (Peste & Sida) e ainda o rock n' roll do Wonderland Club, que prometem levar os ?nimos ao rubro na pista! : Line up : Sexta 15 de Outubro Sala Santiago 21h - Abertura de Portas 22h30 - The Texabilly Rockets (PT) 23h30 - The Poppers (PT) 00h30 - The Fuzztones (USA) 01h30 - Nuno Calado (No DJ's) Sala Hamlet Maria P (Hot Pan Club ) Ian Witchell (Wonderland Club ) Pedro Chau (The Parkinsons) S?bado 16 de Outubro Sala Santiago 21h - Abertura de Portas 22h30 - The Black Needles (BRA) 23h30 - Tiguana Bibles (PT) 00h30 - Los Peyotes (ARG) 01h30 - Rui Maia (X-WIFE) Rude Boy Miranda (The Boom Boom Club) Sala Hamlet Jo?o Pedro Almendra (Peste & Sida) Jo?o Ribas (Censurados - Tara Perdida) Evento Facebook Local: Santiago Alquimista Hora: A partir das 21h00 at? ?s.... Entrada: Pr?-venda (bilhete di?rio) - 12? No dia (bilhete di?rio) - 15? Passe 2 dias - 20? Morada: Rua de Santiago, n?19, 110-493 Lisboa Metro: Rossio / Baixa-Chiado / Martim Moniz Autocarros: 37 El?ctrico: 28 Comboio: Restauradores Mapa: Ver mapa maior Postos de venda: (A partir de sexta-feira, dia 8 de Outubro) Dia: - Groovie Records (Escadinhas da Oliveira, n?3, ao Largo do Carmo) - Louie Louie (R. Nova da Trindade 8, ao Chiado) - Gravershop (Rua da Madalena, N?.80 - Loja D/F) - Two Tone Store (Rua C?ndido dos Reis, n? 14, Cacilhas) - Clockwork (Rua do Crucifixo, n? 32, Baixa Lisboa) Noite: *- Indie Rock Caf? * (Travessa dos Inglesinhos, 49, Bairro Alto) - OFERTA DE UMA CERVEJA no INDIE - Aberto todos os dias, das 23h ?s 02h (sextas e s?bados at? ?s 03h) *- CORTO * (R. da Rosa, 136, Bairro Alto - 'Bar do Corto') - OFERTA DE UMA CERVEJA no CORTO - Aberto de quinta a s?bado, das 23h ?s 02h (sextas e s?bados at? ?s 03h) Contactem os nossos RP's para adquirir bilhetes: Cl?udio Miranda Tlm: 939099067 Email: klaumira at gmail.com Lena Kat Tlm: 939450150 Email: lenakat_msn at hotmail.com Mafalda Tlm: 917904020 Email: mafalda at sailorettes.com Contactos: Void Creations E-mail: info at voidcreations.org @ - ? favor divulgar - -- Para RE-ENVIAR / To FORWARD - http://voidcreationsnewsletter.com/phplist/?p=forward&uid=8796d6f78d5efbb8958965a0e70ab9c8&mid=22 Para REMOVER / To REMOVE - http://voidcreationsnewsletter.com/phplist/?p=unsubscribe&uid=8796d6f78d5efbb8958965a0e70ab9c8 Para MODIFICAR / To MODIFY - http://voidcreationsnewsletter.com/phplist/?p=preferences&uid=8796d6f78d5efbb8958965a0e70ab9c8 -- Powered by PHPlist, www.phplist.com -- -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: powerphplist.png Type: image/png Size: 2408 bytes Desc: not available URL: From reverends at romarrange.com Sun Oct 17 03:02:17 2010 From: reverends at romarrange.com (Brallier Adamaitis) Date: Sun, 17 Oct 2010 01:02:17 -0200 Subject: "Still it is mighty satisfactor Message-ID: <274c-lS2QTQxYB@romarrange.com> A non-text attachment was scrubbed... Name: semifinalist.png Type: image/png Size: 22977 bytes Desc: not available URL: From info at creditportugal.com Sat Oct 16 04:52:24 2010 From: info at creditportugal.com (=?UTF-8?B?RHIuIEx1w61zIENvc3RhIFBlcmVpcmE=?=) Date: Sat, 16 Oct 2010 06:52:24 +0200 Subject: =?UTF-8?B?TGluaGEgUE1FIEludmVzdGUgVkkgLSBBcG9pb3MgRmluYW5jZWlyb3Mgw6BzIEVtcHJlc2Fz?= Message-ID: <287cd4d8fee858562858b7a5545dafe7@markting.tiraduvidas.eu> Your email client cannot read this email. To view it online, please go here: http://markting.tiraduvidas.eu/display.php?M=703557&C=b83904435910d83177dcab6fcbb07b39&S=31&L=11&N=11 To stop receiving these emails:http://markting.tiraduvidas.eu/unsubscribe.php?M=703557&C=b83904435910d83177dcab6fcbb07b39&L=11&N=31 -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 6165e1088db64fc43924091f81c05fa3 Type: image/gif Size: 1759 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 4e8c0fbfcdbc9e0b262816324a995dbd Type: image/gif Size: 697 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ab59c261ac04a0b00e114dae1ccbaa56 Type: image/gif Size: 1000 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 6f8b1323150c87d259df237ead79ecfa Type: image/gif Size: 3617 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 7bd79c629eb18faa13f63774bcf9c7d9 Type: image/gif Size: 62 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: 93558f09827e50a94389685dd26fc20a Type: image/gif Size: 1007 bytes Desc: not available URL: From paletot at vrs.com.au Sun Oct 17 22:30:25 2010 From: paletot at vrs.com.au (Odiase Keitzer) Date: Sun, 17 Oct 2010 23:30:25 +0100 Subject: ely shining star, S Message-ID: A non-text attachment was scrubbed... Name: centisecond.png Type: image/png Size: 22516 bytes Desc: not available URL: From mkt at videosparatreinamento.com.br Mon Oct 18 14:00:16 2010 From: mkt at videosparatreinamento.com.br (=?UTF-8?B?RGFuaWVsIC0gVsOtZGVvcyBkZSBUcmVpbmFtZW50bw==?=) Date: Mon, 18 Oct 2010 10:00:16 -0400 Subject: Pessoa Melhor, Empresa Melhor Message-ID: <7ab95220138d4a0ee41a2925b132696c@sendmail.videosdetreinamento.com> Seu cliente de e-mail n?o pode ler este e-mail. Para visualiz?-lo on-line, por favor, clique aqui: http://sendmail.videosdetreinamento.com/display.php?M=10151452&C=b0030bf1a78c82f2839574f6497e74ec&S=287&L=48&N=28 Para parar de receber nossos Emails:http://sendmail.videosdetreinamento.com/unsubscribe.php?M=10151452&C=b0030bf1a78c82f2839574f6497e74ec&L=48&N=287 Email Marketing -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Mon Oct 18 19:21:27 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 18 Oct 2010 21:21:27 +0200 Subject: gdbstub initial code, v14 Message-ID: <20101018192127.GA14493@redhat.com> Partially implement software watchpoints. Currently ugdb only supports a single watchpoint. Every $Z2 silently deletes the previous one. As for multiple wp's, it is not clear to me how to implement this correctly (and afaics in any case this is nontrivial). I'll try to summarize my questions and send email to archer list. Multitracing is another problem, right now I have no idea how this can work with multiple debuggers. Question: can I use the "current->thread.trap_no == 1" check to figure out reliably whether this SIGTRAP was triggered by TIF_SINGLESTEP ? Oleg. -------------- next part -------------- #include #include #include #include #include #include #include #include static int o_remote_debug; module_param_named(echo, o_remote_debug, bool, 0); #define BUFFER_SIZE 1152 #define PACKET_SIZE 1152 struct pbuf { char *cur, *pkt; char buf[BUFFER_SIZE]; }; static inline void pb_init(struct pbuf *pb) { pb->cur = pb->buf; pb->pkt = NULL; } enum { U_STOP_IDLE = 0, U_STOP_PENDING, U_STOP_SENT, }; #define u_after(a, b) ((long)(b) - (long)(a) < 0) struct ugdb { struct list_head u_processes; struct list_head u_stopped; int u_stop_state; struct mutex u_mutex; spinlock_t u_slock; struct ugdb_thread *u_cur_tinfo, *u_cur_hg, *u_cur_hc; unsigned long u_genctr; wait_queue_head_t u_wait; int u_err; struct pbuf u_pbuf; char u_cbuf[PACKET_SIZE]; int u_clen; sigset_t u_sig_ign; unsigned int u_no_ack:1, u_allstop:1; }; static inline void ugdb_ck_stopped(struct ugdb *ugdb) { spin_lock(&ugdb->u_slock); WARN_ON(!list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_IDLE); WARN_ON(list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_PENDING); spin_unlock(&ugdb->u_slock); } static struct ugdb *ugdb_create(void) { struct ugdb *ugdb; int err; err = -ENODEV; // XXX: ugly. proc_reg_open() should take care. if (!try_module_get(THIS_MODULE)) goto out; err = -ENOMEM; ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL); if (!ugdb) goto put_module; INIT_LIST_HEAD(&ugdb->u_processes); INIT_LIST_HEAD(&ugdb->u_stopped); mutex_init(&ugdb->u_mutex); spin_lock_init(&ugdb->u_slock); init_waitqueue_head(&ugdb->u_wait); pb_init(&ugdb->u_pbuf); return ugdb; put_module: module_put(THIS_MODULE); out: return ERR_PTR(err); } #define P_DETACHING (1 << 1) #define P_ZOMBIE (1 << 2) struct p_wp { unsigned long wp_vers; unsigned long *addr, val; }; static inline void p_wp_init(struct p_wp *p_wp) { } struct ugdb_process { int p_pid; int p_state; struct p_wp p_wp; struct list_head p_threads; struct ugdb *p_ugdb; struct list_head p_processes; }; static inline bool process_alive(struct ugdb_process *process) { return !(process->p_state & P_ZOMBIE); } static inline void mark_process_dead(struct ugdb_process *process) { process->p_state |= P_ZOMBIE; } static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr) { struct ugdb_process *process; process = kzalloc(sizeof(*process), GFP_KERNEL); if (!process) return NULL; process->p_pid = pid_nr; process->p_ugdb = ugdb; INIT_LIST_HEAD(&process->p_threads); list_add_tail(&process->p_processes, &ugdb->u_processes); p_wp_init(&process->p_wp); return process; } #define T_STOP_RUN 0 #define T_STOP_REQ (1 << 0) /* requested by gdb */ #define T_STOP_ALL (1 << 1) /* vCont;c:pX.-1, for report_clone */ #define T_STOP_ACK (1 << 2) /* visible to vStopped */ #define T_STOP_STOPPED (1 << 3) /* reported as stopped to gdb */ /* TASK_TRACED + deactivated ? */ #define T_EV_NONE 0 #define T_EV_EXIT (1 << 24) #define T_EV_SIGN (2 << 24) #define T_EV_TYPE(event) ((0xff << 24) & (event)) #define T_EV_DATA(event) (~(0xff << 24) & (event)) struct t_wp { unsigned long wp_vers; }; #define T_STEP_HARD 1 #define T_STEP_SOFT 2 struct ugdb_thread { int t_tid; int t_stop_state; int t_stop_event; int t_step; // XXX: move me into t_stop_event struct t_wp t_wp; siginfo_t *t_siginfo; struct ugdb *t_ugdb; struct ugdb_process *t_process; unsigned long t_genctr; struct list_head t_threads; struct list_head t_stopped; struct pid *t_spid; struct utrace_engine *t_engine; }; static inline bool thread_alive(struct ugdb_thread *thread) { WARN_ON((thread->t_tid != 0) != process_alive(thread->t_process)); return thread->t_tid != 0; } static inline void mark_thread_dead(struct ugdb_thread *thread) { mark_process_dead(thread->t_process); thread->t_tid = 0; } /* * The thread should be alive, and it can't pass ugdb_report_death() * if the caller holds ugdb->u_mutex. However the tracee can be * reaped anyway, pid_task() can return NULL after detach_pid(). */ static inline struct task_struct *thread_to_task(struct ugdb_thread *thread) { BUG_ON(!thread_alive(thread)); return pid_task(thread->t_spid, PIDTYPE_PID); } static inline void t_wp_init(struct ugdb_thread *thread) { } static struct ugdb_thread *ugdb_create_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (!thread) return NULL; thread->t_tid = pid_vnr(spid); thread->t_spid = get_pid(spid); thread->t_process = process; thread->t_ugdb = process->p_ugdb; thread->t_genctr = thread->t_ugdb->u_genctr; INIT_LIST_HEAD(&thread->t_stopped); list_add_tail(&thread->t_threads, &process->p_threads); t_wp_init(thread); return thread; } static void ugdb_del_stopped(struct ugdb *ugdb, struct ugdb_thread *thread) { if (!list_empty(&thread->t_stopped)) { WARN_ON(!(thread->t_stop_state & T_STOP_ACK)); spin_lock(&ugdb->u_slock); list_del_init(&thread->t_stopped); if (!(thread->t_stop_state & T_STOP_STOPPED)) { if (ugdb->u_stop_state == U_STOP_PENDING && list_empty(&ugdb->u_stopped)) ugdb->u_stop_state = U_STOP_IDLE; } spin_unlock(&ugdb->u_slock); } thread->t_stop_state = T_STOP_RUN; } static void ugdb_destroy_thread(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; ugdb_ck_stopped(ugdb); ugdb_del_stopped(ugdb, thread); /* NULL if attach fails */ if (thread->t_engine) utrace_engine_put(thread->t_engine); list_del(&thread->t_threads); put_pid(thread->t_spid); kfree(thread); } static int ugdb_set_events(struct ugdb_thread *thread, unsigned long events) { WARN_ON(!thread_alive(thread)); events |= (UTRACE_EVENT(CLONE) | UTRACE_EVENT(DEATH) | UTRACE_EVENT_SIGNAL_ALL); //XXX: I think utrace_get_signal() is buggy !!!!!!!!!!!! events |= UTRACE_EVENT(QUIESCE); return utrace_set_events_pid(thread->t_spid, thread->t_engine, events); } static int ugdb_control(struct ugdb_thread *thread, enum utrace_resume_action action) { // XXX: temporary racy check WARN_ON(!thread_alive(thread) && action != UTRACE_DETACH); return utrace_control_pid(thread->t_spid, thread->t_engine, action); } static const struct utrace_engine_ops ugdb_utrace_ops; static void ugdb_detach_thread(struct ugdb_thread *thread, bool running) { int ret; ret = ugdb_control(thread, UTRACE_DETACH); /* engine->flags == 0, it can't run a callback */ if (!running) return; /* callbacks are no longer possible */ if (!ret) return; if (ret == -EINPROGRESS) { /* * We raced with a callback, it can't be ->report_death(). * However, we can not use utrace_barrier_pid(), it can * hang "forever" until the next utrace_resume() if it * sees ->ops == &utrace_detached_ops set by us, but the * tracee is no longer running. * * But: we have no choice. */ do { ret = utrace_barrier_pid(thread->t_spid, thread->t_engine); } while (ret == -ERESTARTSYS); } else { /* * Nothing can help us to synchronize with ->report_death. * We do not know if it was already called or not, we can't * know if it is running. utrace_barrier_pid() can't help, * it can return zero and then later ->report_death() will * be called. Or it can return -ESRCH just because the task * was alredy released and pid_task() == NULL, but this * doesn't mean ->report_death() can't be called later. * * Fortunately, we know that the tracee is dying or dead, * engine->ops should be changed after ugdb_report_death() * returns UTRACE_DETACH. */ while (thread->t_engine->ops == &ugdb_utrace_ops) { schedule_timeout_uninterruptible(1); } } } /* * returns NULL if raced with exit(), or ERR_PTR(). */ static struct ugdb_thread *ugdb_attach_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; struct utrace_engine *engine; struct task_struct *task; thread = ugdb_create_thread(process, spid); if (!thread) goto err; engine = utrace_attach_pid(thread->t_spid, UTRACE_ATTACH_CREATE, &ugdb_utrace_ops, thread); if (IS_ERR(engine)) goto free_thread; thread->t_engine = engine; if (ugdb_set_events(thread, 0)) goto detach_thread; return thread; detach_thread: ugdb_detach_thread(thread, false); free_thread: ugdb_destroy_thread(thread); err: rcu_read_lock(); task = pid_task(spid, PIDTYPE_PID); if (task && task->exit_state) task = NULL; rcu_read_unlock(); return task ? ERR_PTR(-ENOMEM) : NULL; } static inline bool is_subthread(struct ugdb_process *process, struct ugdb_thread *thread) { return thread && thread->t_process == process; } static inline void ugdb_reset_tinfo(struct ugdb *ugdb) { ugdb->u_cur_tinfo = NULL; } static void ugdb_destroy_process(struct ugdb_process *process) { struct ugdb *ugdb = process->p_ugdb; struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); process->p_state |= P_DETACHING; list_del(&process->p_processes); if (is_subthread(process, ugdb->u_cur_hg)) ugdb->u_cur_hg = NULL; if (is_subthread(process, ugdb->u_cur_hc)) ugdb->u_cur_hc = NULL; /* I hope gdb won't do detach from under qfThreadInfo */ if (ugdb->u_cur_tinfo) { printk(KERN_WARNING "ugdb: detach from under qfThreadInfo\n"); ugdb_reset_tinfo(ugdb); } mutex_unlock(&ugdb->u_mutex); while (!list_empty(&process->p_threads)) { thread = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); ugdb_detach_thread(thread, true); ugdb_destroy_thread(thread); } BUG_ON(!list_empty(&process->p_threads)); kfree(process); } static void ugdb_destroy(struct ugdb *ugdb) { struct ugdb_process *process; while (!list_empty(&ugdb->u_processes)) { process = list_first_entry(&ugdb->u_processes, struct ugdb_process, p_processes); ugdb_destroy_process(process); } BUG_ON(!list_empty(&ugdb->u_processes)); BUG_ON(!list_empty(&ugdb->u_stopped)); module_put(THIS_MODULE); kfree(ugdb); } static struct pid *get_next_pid(struct pid *main, struct pid *curr) { struct task_struct *task; struct sighand_struct *sighand; struct pid *next = NULL; rcu_read_lock(); /* * If task/sighand is NULL we return NULL. This is fine if * the caller is get_first_pid(), we should abort attaching. * * But this can also happen if curr was already attached, * and this is wrong. Fortunately, this is very unlikely * case. The attached sub-thread can't pass ->report_death, * if it was reaped the caller of release_task() must be * ptracer who re-parented this thread. */ task = pid_task(curr, PIDTYPE_PID); if (!task) goto unlock_rcu; // XXX: we need lock_task_sighand() but it is not exported, // so we ran race with de_thread(). sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); for (;;) { task = next_thread(task); // XXX: if main is not leader we can race with exec. if (task_pid(task) == main) break; if (!task->exit_state) { next = get_pid(task_pid(task)); break; } } spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); return next; } static struct pid *get_first_pid(struct pid *main) { struct task_struct *leader; rcu_read_lock(); leader = pid_task(main, PIDTYPE_PID); if (leader && leader->exit_state) leader = NULL; rcu_read_unlock(); /* * The group-leader is alive, try to attach. If it exits * before utrace_set_events(), get_first_pid() will be * called again and it will notice ->exit_state != 0. */ if (leader) return get_pid(main); /* * Try to find the live sub-thread. If the whole group * is dead it returns NULL and the caller aborts. */ return get_next_pid(main, main); } static int ugdb_attach_all_threads(struct ugdb *ugdb, struct ugdb_process *process, struct pid *main_pid) { struct ugdb_thread *thread; struct pid *curr_pid; mutex_lock(&ugdb->u_mutex); for (;;) { curr_pid = get_first_pid(main_pid); if (!curr_pid) goto abort; thread = ugdb_attach_thread(process, curr_pid); put_pid(curr_pid); if (IS_ERR(thread)) goto abort; if (thread) break; } for (;;) { struct pid *next_pid; next_pid = get_next_pid(main_pid, curr_pid); if (!next_pid) break; thread = ugdb_attach_thread(process, next_pid); put_pid(next_pid); if (IS_ERR(thread)) goto abort; if (!thread) continue; curr_pid = next_pid; } mutex_unlock(&ugdb->u_mutex); return 0; abort: mutex_unlock(&ugdb->u_mutex); return -1; } static int ugdb_attach(struct ugdb *ugdb, int pid_nr) { struct pid *main_pid; struct ugdb_process *process; int err; // XXX: check if exists // XXX: check if group leader ? err = -ESRCH; main_pid = find_get_pid(pid_nr); if (!main_pid) goto out; err = -ENOMEM; process = ugdb_create_process(ugdb, pid_nr); if (!process) goto free_pid; err = ugdb_attach_all_threads(ugdb, process, main_pid); if (err) ugdb_destroy_process(process); free_pid: put_pid(main_pid); out: return err; } static struct ugdb_process *ugdb_find_process(struct ugdb *ugdb, int pid) { struct ugdb_process *process; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (process->p_pid == pid) return process; } return NULL; } static struct ugdb_thread *ugdb_find_thread(struct ugdb *ugdb, int pid, int tid) { struct ugdb_process *process; struct ugdb_thread *thread; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (!tid || thread->t_tid == tid) return thread; } if (pid) break; } return NULL; } static int ugdb_detach(struct ugdb *ugdb, int pid) { struct ugdb_process *process = ugdb_find_process(ugdb, pid); if (!process) return -1; ugdb_destroy_process(process); return 0; } #define CUR_TINFO_END ((struct ugdb_thread *)1) static struct ugdb_thread *ugdb_advance_tinfo(struct ugdb *ugdb) { struct ugdb_thread *cur, *nxt; struct ugdb_process *process; cur = ugdb->u_cur_tinfo; if (cur == CUR_TINFO_END) { ugdb->u_cur_tinfo = NULL; return NULL; } if (!cur) { list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { cur = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } if (!cur) return NULL; } process = cur->t_process; if (list_is_last(&cur->t_threads, &process->p_threads)) { nxt = CUR_TINFO_END; list_for_each_entry_continue(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { nxt = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } } else { nxt = list_first_entry(&cur->t_threads, struct ugdb_thread, t_threads); } ugdb->u_cur_tinfo = nxt; return cur; } // ----------------------------------------------------------------------------- static bool ugdb_add_stopped(struct ugdb_thread *thread, int stop_event) { struct ugdb *ugdb = thread->t_ugdb; bool ret = false; ugdb_ck_stopped(ugdb); spin_lock(&ugdb->u_slock); if (stop_event == T_EV_NONE) { if (WARN_ON(thread->t_stop_state & T_STOP_ACK)) goto unlock; if (WARN_ON(!list_empty(&thread->t_stopped))) goto unlock; /* raced with ugdb_cont_thread() */ if (!(thread->t_stop_state & T_STOP_REQ)) goto unlock; } if (thread->t_stop_state & T_STOP_ACK) { if (thread->t_stop_state & T_STOP_STOPPED) /* * Alas, we can't report this event. We already * reported T00 and there is no way to inform gdb * the state of tracee was changed. */ goto unlock; } else { WARN_ON(thread->t_stop_state & T_STOP_STOPPED); thread->t_stop_state |= T_STOP_ACK; list_add_tail(&thread->t_stopped, &ugdb->u_stopped); if (ugdb->u_stop_state == U_STOP_IDLE) { ugdb->u_stop_state = U_STOP_PENDING; wake_up_all(&ugdb->u_wait); } } thread->t_stop_event = stop_event; ret = true; unlock: spin_unlock(&ugdb->u_slock); return ret; } static void ugdb_process_exit(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; int status; BUG_ON(!thread_alive(thread)); ugdb_del_stopped(ugdb, thread); mark_thread_dead(thread); // XXX: OOPS, we can't read ->signal->group_exit_code !!! status = current->exit_code; if (ugdb_add_stopped(thread, T_EV_EXIT | status)) return; WARN_ON(1); } static int ugdb_stop_thread(struct ugdb_thread *thread, bool all) { struct ugdb *ugdb = thread->t_ugdb; int err; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); if (thread->t_stop_state != T_STOP_RUN) { if (!all || (thread->t_stop_state & T_STOP_ALL)) return 0; /* * Otherwise we should set T_STOP_ALL anyway, * * (gdb) interrupt & * (gbd) interrupt -a & * * to ensure -a actually works if it races with clone. */ } err = -EALREADY; spin_lock(&ugdb->u_slock); if (thread->t_stop_state == T_STOP_RUN) { thread->t_stop_state = T_STOP_REQ; err = 0; } /* * We hold ugdb->u_mutex, we can't race with ugdb_report_clone(). * ugdb->u_slock protects us against ugdb_add_stopped(). We can * change ->t_stop_state even if we did not initiate this stop. */ if (all) thread->t_stop_state |= T_STOP_ALL; spin_unlock(&ugdb->u_slock); if (err) return 0; // XXX: we don't do UTRACE_STOP! this means we can't // stop TASK_STOPEED task. Need to discuss jctl issues. // if we do UTRACE_STOP we should call ugdb_add_stopped(). ugdb_set_events(thread, UTRACE_EVENT(QUIESCE)); err = ugdb_control(thread, UTRACE_INTERRUPT); if (err && err != -EINPROGRESS) return err; return 1; } static int ugdb_cont_thread(struct ugdb_thread *thread, bool all, int t_step) { struct ugdb *ugdb = thread->t_ugdb; int ret; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); // XXX: gdb shouldn't explicitly cont an unreported thread WARN_ON(!all && !(thread->t_stop_state & T_STOP_STOPPED)); if (thread->t_stop_state == T_STOP_RUN) return 0; spin_lock(&ugdb->u_slock); /* * Nothing to do except clear the pending T_STOP_REQ. */ ret = 0; if (!(thread->t_stop_state & T_STOP_ACK)) goto set_run; /* * Alas. Thanks to remote protocol, we can't cont this * thread. We probably already sent the notification, we * can do nothing except ack that %Stop later in response * to vStopped. * * OTOH, gdb shouldn't send 'c' if this thread was not * reported as stopped. However, this means that gdb can * see the new %Stop:T00 notification after vCont;c:pX.-1, * it should handle this case correctly anyway. I hope. * * If this stop was not initiated by gdb we should not * cancel it too, this event should be reported first. */ ret = -1; if (!(thread->t_stop_state & T_STOP_STOPPED)) goto unlock; ret = 1; list_del_init(&thread->t_stopped); set_run: thread->t_stop_state = T_STOP_RUN; unlock: spin_unlock(&ugdb->u_slock); if (ret >= 0) { unsigned long events = 0; enum utrace_resume_action action = UTRACE_RESUME; thread->t_step = t_step; if (t_step) { /* to correctly step over syscall insn */ events |= UTRACE_EVENT(SYSCALL_EXIT); action = UTRACE_SINGLESTEP; } // XXX: OK, this all is racy, and I do not see any // solution except: implement UTRACE_STOP_STICKY and // move this code up under the lock, or add // utrace_engine_ops->notify_stopped(). // 1. UTRACE_RESUME is racy, this is fixeable. // 2. we need utrace_barrier() to close the race // with the callback which is going to return // UTRACE_STOP, but: // a) we can deadlock (solveable) // b) in this case UTRACE_RESUME can race with // another stop initiated by tracee itself. ugdb_set_events(thread, events); ugdb_control(thread, action); } return ret; } static struct ugdb_thread *ugdb_next_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread = NULL; // XXX: temporary racy check WARN_ON(ugdb->u_stop_state == U_STOP_IDLE); spin_lock(&ugdb->u_slock); if (list_empty(&ugdb->u_stopped)) { ugdb->u_stop_state = U_STOP_IDLE; } else { ugdb->u_stop_state = U_STOP_SENT; thread = list_first_entry(&ugdb->u_stopped, struct ugdb_thread, t_stopped); thread->t_stop_state |= T_STOP_STOPPED; list_del_init(&thread->t_stopped); } spin_unlock(&ugdb->u_slock); return thread; } // ----------------------------------------------------------------------------- static bool ugdb_stop_pending(struct ugdb_thread *thread) { if (!(thread->t_stop_state & T_STOP_REQ)) return false; if (!(thread->t_stop_state & T_STOP_ACK)) return ugdb_add_stopped(thread, T_EV_NONE); return true; } static u32 ugdb_report_quiesce(u32 action, struct utrace_engine *engine, unsigned long event) { struct ugdb_thread *thread = engine->data; WARN_ON(!thread_alive(thread)); /* ensure SIGKILL can't race with stop/cont in progress */ if (event != UTRACE_EVENT(DEATH)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP; } return utrace_resume_action(action); } static int cont_signal(struct ugdb_thread *thread, struct k_sigaction *return_ka) { int signr = T_EV_DATA(thread->t_stop_event); siginfo_t *info = thread->t_siginfo; thread->t_siginfo = NULL; if (WARN_ON(!valid_signal(signr))) return 0; if (!signr) return signr; /* * Update the siginfo structure if the signal has changed. */ if (info->si_signo != signr) { info->si_signo = signr; info->si_errno = 0; info->si_code = SI_USER; info->si_pid = 0; info->si_uid = 0; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, info, current); signr = 0; } else { spin_lock_irq(¤t->sighand->siglock); *return_ka = current->sighand->action[signr - 1]; spin_unlock_irq(¤t->sighand->siglock); } return signr; } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info); static u32 ugdb_report_signal(u32 action, struct utrace_engine *engine, struct pt_regs *regs, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) { struct ugdb_thread *thread = engine->data; struct ugdb *ugdb = thread->t_ugdb; int signr; WARN_ON(!thread_alive(thread)); switch (utrace_signal_action(action)) { case UTRACE_SIGNAL_HANDLER: if (WARN_ON(thread->t_siginfo)) thread->t_siginfo = NULL; if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } /* Fall through */ default: if (orig_ka) break; /* * It was UTRACE_SIGNAL_REPORT, but another tracer has * changed utrace_report->result to deliver or stop. * Fall through. */ case UTRACE_SIGNAL_REPORT: if (!thread->t_siginfo) { /* UTRACE_INTERRUPT from ugdb_report_syscall_exit() */ if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } } else { if (WARN_ON(thread->t_siginfo != info)) return action; WARN_ON(T_EV_TYPE(thread->t_stop_event) != T_EV_SIGN); signr = cont_signal(thread, return_ka); if (signr) { /* * Consider: * * (gdb) signal SIG & * (gdb) interrupt * * We shouldn't miss the new stop request, so * we do not return from here. */ action = UTRACE_RESUME | UTRACE_SIGNAL_DELIVER; } } if (ugdb_stop_pending(thread)) return UTRACE_STOP | utrace_signal_action(action); if (thread->t_step) return UTRACE_SINGLESTEP | utrace_signal_action(action); return action; } WARN_ON(thread->t_siginfo); signr = info->si_signo; if (WARN_ON(!signr || !valid_signal(signr))) return action; if (wp_next_soft_trap(thread, info)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP | UTRACE_SIGNAL_IGN; return UTRACE_SINGLESTEP | UTRACE_SIGNAL_IGN; } if (sigismember(&ugdb->u_sig_ign, signr)) return action; if (ugdb_add_stopped(thread, T_EV_SIGN | signr)) { thread->t_siginfo = info; /* * Make sure the subsequent UTRACE_SIGNAL_REPORT clears * ->t_siginfo before return from get_signal_to_deliver(). */ if (utrace_control(current, engine, UTRACE_INTERRUPT)) WARN_ON(1); return UTRACE_STOP | UTRACE_SIGNAL_IGN; } /* * We already reported T00 to gdb. We can't change our state, * we are already stopped from gdb pov. Push back this signal * to report it later, after "continue". * * Not multitrace-friendly. */ return UTRACE_STOP | UTRACE_SIGNAL_REPORT | UTRACE_SIGNAL_HOLD; } static u32 ugdb_report_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { struct ugdb_thread *thread = engine->data; if (thread->t_step) return UTRACE_INTERRUPT; printk(KERN_INFO "ugdb: unexpected SYSCALL_EXIT\n"); return action; } static bool is_already_attached(struct ugdb_process *process, struct task_struct *task) { struct ugdb_thread *thread; if (likely(!task_utrace_flags(task))) return false; /* * Currently there is no way to know if it was attached by us. * We can't trust utrace_attach_task(UTRACE_ATTACH_MATCH_OPS), * ugdb attaches without UTRACE_ATTACH_EXCLUSIVE. We have to * check every attached thread. * * This is really bad, but without multitracing this can only * happen in unlikely case right after ugdb_attach_all_threads(). */ list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_spid == task_pid(task)) return true; } return false; } static void ugdb_wp_clone(struct ugdb_thread *thread); static u32 ugdb_report_clone(u32 action, struct utrace_engine *engine, unsigned long clone_flags, struct task_struct *task) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; struct ugdb_thread *new_thread; WARN_ON(!thread_alive(thread)); if (!(clone_flags & CLONE_THREAD)) goto out; mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; /* * This can only happen if we raced with ugdb_attach() which * could attach both current and the new PF_STARTING child. */ if (unlikely(is_already_attached(process, task))) goto unlock; new_thread = ugdb_attach_thread(process, task_pid(task)); BUG_ON(!new_thread); if (WARN_ON(IS_ERR(new_thread))) goto unlock; if (thread->t_stop_state & T_STOP_ALL) ugdb_stop_thread(new_thread, false); else ugdb_wp_clone(new_thread); unlock: mutex_unlock(&ugdb->u_mutex); out: return utrace_resume_action(action); } static u32 ugdb_report_death(struct utrace_engine *engine, bool group_dead, int signal) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; WARN_ON(!thread_alive(thread)); mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; if (ugdb->u_cur_hg == thread) ugdb->u_cur_hg = NULL; if (ugdb->u_cur_hc == thread) ugdb->u_cur_hc = NULL; if (ugdb->u_cur_tinfo == thread) ugdb_advance_tinfo(ugdb); if (list_is_singular(&process->p_threads)) ugdb_process_exit(thread); else ugdb_destroy_thread(thread); unlock: mutex_unlock(&ugdb->u_mutex); return UTRACE_DETACH; } static const struct utrace_engine_ops ugdb_utrace_ops = { .report_quiesce = ugdb_report_quiesce, .report_signal = ugdb_report_signal, .report_syscall_exit = ugdb_report_syscall_exit, .report_clone = ugdb_report_clone, .report_death = ugdb_report_death, }; // ----------------------------------------------------------------------------- static inline int pb_size(struct pbuf *pb) { return pb->cur - pb->buf; } static inline int pb_room(struct pbuf *pb) { return pb->buf + BUFFER_SIZE - pb->cur; } static inline void pb_putc(struct pbuf *pb, char c) { if (WARN_ON(pb->cur >= pb->buf + BUFFER_SIZE)) return; *pb->cur++ = c; } static void pb_memcpy(struct pbuf *pb, const void *data, int size) { if (WARN_ON(size > pb_room(pb))) return; memcpy(pb->cur, data, size); pb->cur += size; } static inline void pb_puts(struct pbuf *pb, const char *s) { pb_memcpy(pb, s, strlen(s)); } static inline void pb_putb(struct pbuf *pb, unsigned char val) { static char hex[] = "0123456789abcdef"; pb_putc(pb, hex[(val & 0xf0) >> 4]); pb_putc(pb, hex[(val & 0x0f) >> 0]); } static void pb_putbs(struct pbuf *pb, const char *data, int size) { while (size--) pb_putb(pb, *data++); } static inline void __pb_start(struct pbuf *pb, char pref) { WARN_ON(pb->pkt); pb_putc(pb, pref); pb->pkt = pb->cur; } static inline void pb_start(struct pbuf *pb) { return __pb_start(pb, '$'); } static inline void pb_cancel(struct pbuf *pb) { if (WARN_ON(!pb->pkt)) return; pb->cur = pb->pkt - 1; pb->pkt = NULL; } static void pb_end(struct pbuf *pb) { unsigned char csm = 0; char *pkt = pb->pkt; pb->pkt = NULL; if (WARN_ON(!pkt)) return; while (pkt < pb->cur) { /* pb_qfer() can write '%' */ WARN_ON(*pkt == '$' || *pkt == '#'); csm += (unsigned char)*pkt++; } pb_putc(pb, '#'); pb_putb(pb, csm); } static inline void pb_packs(struct pbuf *pb, const char *s) { pb_start(pb); pb_puts(pb, s); pb_end(pb); } static void __attribute__ ((format(printf, 3, 4))) __pb_format(struct pbuf *pb, bool whole_pkt, const char *fmt, ...) { int room = pb_room(pb), size; va_list args; if (whole_pkt) pb_start(pb); va_start(args, fmt); size = vsnprintf(pb->cur, room, fmt, args); va_end(args); if (WARN_ON(size > room)) return; pb->cur += size; if (whole_pkt) pb_end(pb); } #define pb_printf(pb, args...) __pb_format((pb), false, args) #define pb_packf(pb, args...) __pb_format((pb), true, args) static int pb_qfer(struct pbuf *pb, const void *_data, int len, bool more) { const unsigned char *data = _data; int i; if (pb_room(pb) < 3 + len * 2) { WARN_ON(1); return -EOVERFLOW; } pb_start(pb); pb_putc(pb, more ? 'm' : 'l'); for (i = 0; i < len; ++i) { unsigned char c = data[i]; if (c == '$' || c == '#' || c == '}' || c == '*') { pb_putc(pb, '}'); c ^= 0x20; } pb_putc(pb, c); } pb_end(pb); return 0; } // XXX: improve me! static inline int pb_max_bs_size(struct pbuf *pb) { int size = pb_room(pb) - 4; return size > 0 ? size / 2 : 0; } static inline void *pb_alloc_bs(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < 2 * size + 4)) return NULL; return pb->cur + size + 1; } static inline void *pb_alloc_tmp(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < size)) return NULL; return pb->cur + BUFFER_SIZE - size; } static inline void pb_flush(struct pbuf *pb, int size) { int keep = pb_size(pb) - size; if (keep) memmove(pb->buf, pb->buf + size, keep); pb->cur -= size; } static int pb_copy_to_user(struct pbuf *pb, char __user *ubuf, int size) { int copy = min(size, pb_size(pb)); if (!copy) return -EAGAIN; if (o_remote_debug) printk(KERN_INFO "<= %.*s\n", min(copy, 64), pb->buf); if (copy_to_user(ubuf, pb->buf, copy)) return -EFAULT; pb_flush(pb, copy); return copy; } // ----------------------------------------------------------------------------- static typeof(access_process_vm) *u_access_process_vm; static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static const char *handle_z(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; bool insert; int type; struct utrace_examiner exam; struct task_struct *task; struct p_wp *p_wp; insert = (*cmd++ == 'Z'); if (sscanf(cmd, "%d,%lx,%lx", &type, &addr, &size) != 3) return "E01"; if (type != 2) return ""; task = ugdb_prepare_examine(ugdb, &exam); if (!task) return "E01"; p_wp = &ugdb->u_cur_hg->t_process->p_wp; if (insert) { u_access_process_vm(task, addr, &p_wp->val, sizeof(long), 0); p_wp->addr = (void*)addr; } else { p_wp->addr = NULL; } ugdb_finish_examine(ugdb, &exam); return "OK"; } static bool ck_wp_changed(struct ugdb_thread *thread) { struct p_wp *p_wp = &thread->t_process->p_wp; unsigned long *addr; unsigned long val; if (u_after(p_wp->wp_vers, thread->t_wp.wp_vers)) return true; addr = p_wp->addr; barrier(); if (!addr) return false; if (get_user(val, addr)) // XXX: ???? return false; if (val == p_wp->val) return false; p_wp->wp_vers++; p_wp->val = val; return true; } static inline bool is_wp_active(struct ugdb_thread *thread) { return thread->t_process->p_wp.addr != NULL; } static bool wp_soft_trap(struct ugdb_thread *thread) { if (!is_wp_active(thread)) return false; thread->t_wp.wp_vers = thread->t_process->p_wp.wp_vers; return true; } static inline bool is_wp_pending(struct ugdb_thread *thread) { if (!is_wp_active(thread)) return false; return u_after(thread->t_process->p_wp.wp_vers, thread->t_wp.wp_vers); } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info) { if (!is_wp_active(thread)) return false; if (ck_wp_changed(thread)) return false; return info->si_signo == SIGTRAP && thread->t_step == T_STEP_SOFT && // XXX: this filters out do_int3() only. // XXX: this is not right, we probably need // to check trap_no == 1, but then we need // unexported user_single_step_siginfo() for // ugdb_report_signal(). current->thread.trap_no != 3; } static void ugdb_wp_clone(struct ugdb_thread *thread) { if (wp_soft_trap(thread)) { thread->t_step = T_STEP_SOFT; ugdb_set_events(thread, UTRACE_EVENT(SYSCALL_EXIT)); ugdb_control(thread, UTRACE_SINGLESTEP); } } // ----------------------------------------------------------------------------- // XXX: include/gdb/signals.h:target_signal // incomplete: 7, 29, rt? static int to_gdb_sigmap[] = { [SIGHUP] = 1, [SIGINT] = 2, [SIGQUIT] = 3, [SIGILL] = 4, [SIGTRAP] = 5, [SIGABRT] = 6, [SIGIOT] = 0, /* ??? */ [SIGBUS] = 10, [SIGFPE] = 8, [SIGKILL] = 9, [SIGUSR1] = 30, [SIGSEGV] = 11, [SIGUSR2] = 31, [SIGPIPE] = 13, [SIGALRM] = 14, [SIGTERM] = 15, [SIGSTKFLT] = 0, /* ??? */ [SIGCHLD] = 20, [SIGCONT] = 19, [SIGSTOP] = 17, [SIGTSTP] = 18, [SIGTTIN] = 21, [SIGTTOU] = 22, [SIGURG] = 16, [SIGXCPU] = 24, [SIGXFSZ] = 25, [SIGVTALRM] = 26, [SIGPROF] = 27, [SIGWINCH] = 28, [SIGIO] = 23, [SIGPWR] = 32, [SIGSYS] = 12, }; static int sig_to_gdb(unsigned sig) { if (sig < ARRAY_SIZE(to_gdb_sigmap) && to_gdb_sigmap[sig]) return to_gdb_sigmap[sig]; return sig; } static int sig_from_gdb(unsigned sig) { int i; // XXX: valid_signal() is wrong, gdb has its own idea // about signals. fix to_gdb_sigmap[]. if (!sig || !valid_signal(sig)) return 0; for (i = 0; i < ARRAY_SIZE(to_gdb_sigmap); i++) { if (to_gdb_sigmap[i] == sig) return i; } return sig; } static int ugdb_report_stopped(struct ugdb *ugdb, bool async) { struct ugdb_thread *thread; int pid, tid, event, data; struct pbuf *pb; char ex_r; mutex_lock(&ugdb->u_mutex); thread = ugdb_next_stopped(ugdb); if (!thread) goto unlock; event = thread->t_stop_event; WARN_ON(thread_alive(thread) != (T_EV_TYPE(event) != T_EV_EXIT)); pid = thread->t_process->p_pid; tid = thread->t_tid; unlock: mutex_unlock(&ugdb->u_mutex); if (!thread) return false; pb = &ugdb->u_pbuf; // XXX: damn, cleanup me... if (async) { __pb_start(pb, '%'); pb_puts(pb, "Stop:"); } else { pb_start(pb); } data = T_EV_DATA(event); switch (T_EV_TYPE(event)) { case T_EV_EXIT: if (data & 0xff) { data = sig_to_gdb(data & 0xff); ex_r = 'X'; } else { data >>= 8; ex_r = 'W'; } pb_printf(pb, "%c%x;process:%x", ex_r, data, pid); ugdb_destroy_process(thread->t_process); break; case T_EV_SIGN: case T_EV_NONE: pb_printf(pb, "T%02xthread:p%x.%x;", sig_to_gdb(data), pid, tid); // !!!!!!!!!!!!!!!!!!!!!! XXX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (is_wp_pending(thread)) pb_printf(pb, "watch:%p;", thread->t_process->p_wp.addr); break; default: printk(KERN_INFO "ugdb: bad stop event %x\n", event); } pb_end(pb); return true; } const char *handle_vstopped(struct ugdb *ugdb) { if (ugdb->u_stop_state != U_STOP_SENT) return "E01"; if (ugdb_report_stopped(ugdb, false)) return NULL; return "OK"; } static const char *handle_thread_info(struct ugdb *ugdb, bool start) { struct ugdb_thread *thread; int pid = 0, tid; mutex_lock(&ugdb->u_mutex); if (start) ugdb_reset_tinfo(ugdb); else if (!ugdb->u_cur_tinfo) printk(KERN_INFO "ugdb: unexpected qsThreadInfo\n"); thread = ugdb_advance_tinfo(ugdb); if (thread) { pid = thread->t_process->p_pid; tid = thread->t_tid; } mutex_unlock(&ugdb->u_mutex); if (!pid) return start ? "E01" : "l"; pb_packf(&ugdb->u_pbuf, "mp%x.%x", pid, tid); return NULL; } static char *parse_xid(char *str, int *ppid, bool multi) { if (*str == '-') { str++; if (multi && *str++ == '1') *ppid = -1; else str = NULL; } else { char *cur = str; *ppid = simple_strtoul(cur, &str, 16); if (str == cur) str = NULL; } return str; } static char *parse_pid_tid(char *str, int *ppid, int *ptid, bool multi) { if (*str++ != 'p') return NULL; str = parse_xid(str, ppid, multi); if (!str) return NULL; if (*str++ != '.') return NULL; str = parse_xid(str, ptid, multi); if (!str) return NULL; return str; } static const char *handle_set_cur(struct ugdb *ugdb, char *cmd) { struct ugdb_thread **pthread; int pid, tid; switch (*cmd++) { case 'g': pthread = &ugdb->u_cur_hg; break; case 'c': pthread = &ugdb->u_cur_hc; break; default: goto err; } if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); *pthread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (*pthread) return "OK"; err: return "E01"; } static const char *handle_ck_alive(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; int pid = 0, tid; if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); thread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (thread) return "OK"; err: return "E01"; } static int parse_pid(char *str) { int pid; if (!parse_xid(str, &pid, false)) return 0; return pid; } static const char *handle_vattach(struct ugdb *ugdb, char *cmd) { int pid = parse_pid(cmd); if (pid && !ugdb_attach(ugdb, pid)) return "OK"; return "E01"; } static const char *handle_detach(struct ugdb *ugdb, char *cmd) { int pid; if (*cmd++ != ';') goto err; pid = parse_pid(cmd); if (pid && !ugdb_detach(ugdb, pid)) return "OK"; err: return "E01"; } typedef int (*each_func_t)(struct ugdb_thread *, void *); static int ugdb_do_each_thread(struct ugdb *ugdb, int pid, int tid, each_func_t func, void *arg) { struct ugdb_process *process; struct ugdb_thread *thread; int ret = -ESRCH; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid > 0 && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (tid > 0 && thread->t_tid != tid) continue; ret = func(thread, arg); if (ret) goto out; if (tid >= 0) break; } if (pid >= 0) break; } out: return ret; } static int thread_cont_signal(struct ugdb_thread *thread, int signr) { /* * T_STOP_STOPPED was set under ->u_slock so we can't race * with ugdb_add_stopped() and get the wrong t_stop_event. * And, the tracee never changes it after T_STOP_STOPPED. */ switch (T_EV_TYPE(thread->t_stop_event)) { case T_EV_SIGN: WARN_ON(!T_EV_DATA(thread->t_stop_event)); thread->t_stop_event = T_EV_SIGN | signr; break; default: if (!signr) break; // XXX: temporary hack, will be reported. // but perhaps this is what we want ??? kill_pid(thread->t_spid, signr, 0); break; } return 0; } static int ugdb_resume_thread(struct ugdb_thread *thread, int signr, bool step, bool all) { int t_step; int ret = 0; /* * Otherwise I do not know what to do if sig/step, and anyway * I don't think gdb can try to cont a thread which was not * reported as stopped. */ if (!(thread->t_stop_state & T_STOP_STOPPED)) return ret; ret = thread_cont_signal(thread, signr); if (ret < 0) return ret; t_step = 0; if (wp_soft_trap(thread)) t_step = T_STEP_SOFT; if (step) t_step = T_STEP_HARD; return ugdb_cont_thread(thread, all, t_step); } static const char *handle_c(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; const char *rc = "E01"; int gdbsig, signr = 0; bool step; step = (*cmd == 'S' || *cmd == 's'); switch (*cmd++) { case 'C': case 'S': gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) return rc; signr = sig_from_gdb(gdbsig); if (!signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); if (*cmd == ';') ++cmd; /* fall */ case 'c': case 's': if (!*cmd) break; printk(KERN_INFO "ugdb: $c ADDR not implemented\n"); return rc; break; } mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hc; if (!thread) goto unlock; if (ugdb_resume_thread(thread, signr, step, false) <= 0) goto unlock; /* Suprise: non-stop should not reply! */ rc = NULL; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } struct vcont_arg { int pid, tid; bool intr; int signr; bool step; }; static char* parse_vcont_arg(char *cmd, struct vcont_arg *vcont) { vcont->intr = false; vcont->signr = 0; switch (*cmd++) { case 't': vcont->intr = true; break; case 'S': vcont->signr = 1; case 's': vcont->step = true; break; case 'C': vcont->signr = 1; case 'c': vcont->step = false; break; default: goto err; } if (vcont->signr) { int gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) goto err; vcont->signr = sig_from_gdb(gdbsig); if (!vcont->signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); } vcont->pid = -1; vcont->tid = -1; if (*cmd == ':') { cmd = parse_pid_tid(cmd + 1, &vcont->pid, &vcont->tid, true); if (!cmd) goto err; } return cmd; err: return NULL; } static int do_vcont_thread(struct ugdb_thread *thread, void *arg) { struct vcont_arg *vcont = arg; unsigned long genctr; bool all; int err; genctr = thread->t_ugdb->u_genctr; if (genctr == thread->t_genctr) return 0; WARN_ON_ONCE(u_after(thread->t_genctr, genctr)); thread->t_genctr = genctr; all = (vcont->tid < 0); if (vcont->intr) err = ugdb_stop_thread(thread, all); else err = ugdb_resume_thread(thread, vcont->signr, vcont->step, all); if (err < 0) return err; return 0; } static const char *handle_vcont(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; switch (*cmd) { case ';': break; case '?': return "vCont;t;c;C;s;S"; default: return "E01"; } mutex_lock(&ugdb->u_mutex); ugdb->u_genctr++; while (*cmd) { struct vcont_arg vcont_arg; int err; if (*cmd++ != ';') goto unlock; cmd = parse_vcont_arg(cmd, &vcont_arg); if (!cmd) goto unlock; err = ugdb_do_each_thread(ugdb, vcont_arg.pid, vcont_arg.tid, do_vcont_thread, &vcont_arg); if (err) goto unlock; } rc = "OK"; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } static const char *handle_qpass_signals(struct ugdb *ugdb, char *cmd) { sigset_t *set = &ugdb->u_sig_ign; sigemptyset(set); while (*cmd) { char *end; int sig = simple_strtoul(cmd, &end, 16); if (cmd == end || *end != ';') return "E01"; cmd = end + 1; sig = sig_from_gdb(sig); if (!sig) // XXX: to_gdb_sigmap[] incomplete... // return "E01"; continue; sigaddset(set, sig); } return "OK"; } // ----------------------------------------------------------------------------- static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { struct ugdb_thread *thread; struct task_struct *task; int err; mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hg; if (!thread || !(thread->t_stop_state & T_STOP_STOPPED)) goto err; // XXX: u_cur_hg can't exit, we hold the mutex task = thread_to_task(thread); if (!task) goto err; for (;;) { if (fatal_signal_pending(current)) goto err; err = utrace_prepare_examine(task, thread->t_engine, exam); if (!err) break; if (err == -ESRCH) goto err; schedule_timeout_interruptible(1); } return task; err: mutex_unlock(&ugdb->u_mutex); return NULL; } // XXX: we hold the mutex in between, but only because we can't // use get_task_struct/put_task_struct. static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { // XXX: u_cur_hg can't exit, we hold the mutex struct ugdb_thread *thread = ugdb->u_cur_hg; struct task_struct *task = thread_to_task(thread); int ret = -ESRCH; if (task) ret = utrace_finish_examine(task, thread->t_engine, exam); mutex_unlock(&ugdb->u_mutex); return ret; } #define REGSET_GENERAL 0 #define REGSET_FP 1 #define MAX_REG_SIZE 16 struct gdbreg { unsigned short gdb_size, gdb_offs, rs_setno, usr_offs; }; // gdb/gdbserver/i387-fp.c:i387_fxsave struct gdb_i387_fxsave { unsigned short fctrl; unsigned short fstat; unsigned short ftag; unsigned short fop; unsigned int fioff; unsigned short fiseg; unsigned short pad1; unsigned int fooff; unsigned short foseg; unsigned short pad12; unsigned int mxcsr; unsigned int pad3; unsigned char st_space[128]; unsigned char xmm_space[256]; }; #define FPU__(mem) \ .rs_setno = REGSET_FP, \ .usr_offs = offsetof(struct gdb_i387_fxsave, mem) #define GEN__(mem) \ .rs_setno = REGSET_GENERAL, \ .usr_offs = offsetof(struct user_regs_struct, mem) /* generated from gdb/regformats/reg-x86-64-linux.dat */ struct gdbreg gdb_regmap_64[] = { [ 0] = { .gdb_size = 8, .gdb_offs = 0, GEN__(ax) }, [ 1] = { .gdb_size = 8, .gdb_offs = 8, GEN__(bx) }, [ 2] = { .gdb_size = 8, .gdb_offs = 16, GEN__(cx) }, [ 3] = { .gdb_size = 8, .gdb_offs = 24, GEN__(dx) }, [ 4] = { .gdb_size = 8, .gdb_offs = 32, GEN__(si) }, [ 5] = { .gdb_size = 8, .gdb_offs = 40, GEN__(di) }, [ 6] = { .gdb_size = 8, .gdb_offs = 48, GEN__(bp) }, [ 7] = { .gdb_size = 8, .gdb_offs = 56, GEN__(sp) }, [ 8] = { .gdb_size = 8, .gdb_offs = 64, GEN__(r8) }, [ 9] = { .gdb_size = 8, .gdb_offs = 72, GEN__(r9) }, [10] = { .gdb_size = 8, .gdb_offs = 80, GEN__(r10) }, [11] = { .gdb_size = 8, .gdb_offs = 88, GEN__(r11) }, [12] = { .gdb_size = 8, .gdb_offs = 96, GEN__(r12) }, [13] = { .gdb_size = 8, .gdb_offs = 104, GEN__(r13) }, [14] = { .gdb_size = 8, .gdb_offs = 112, GEN__(r14) }, [15] = { .gdb_size = 8, .gdb_offs = 120, GEN__(r15) }, [16] = { .gdb_size = 8, .gdb_offs = 128, GEN__(ip) }, [17] = { .gdb_size = 4, .gdb_offs = 136, GEN__(flags) }, [18] = { .gdb_size = 4, .gdb_offs = 140, GEN__(cs) }, [19] = { .gdb_size = 4, .gdb_offs = 144, GEN__(ss) }, [20] = { .gdb_size = 4, .gdb_offs = 148, GEN__(ds) }, [21] = { .gdb_size = 4, .gdb_offs = 152, GEN__(es) }, [22] = { .gdb_size = 4, .gdb_offs = 156, GEN__(fs) }, [23] = { .gdb_size = 4, .gdb_offs = 160, GEN__(gs) }, [24] = { .gdb_size = 10, .gdb_offs = 164, FPU__(st_space[0]) }, [25] = { .gdb_size = 10, .gdb_offs = 174, FPU__(st_space[16]) }, [26] = { .gdb_size = 10, .gdb_offs = 184, FPU__(st_space[32]) }, [27] = { .gdb_size = 10, .gdb_offs = 194, FPU__(st_space[48]) }, [28] = { .gdb_size = 10, .gdb_offs = 204, FPU__(st_space[64]) }, [29] = { .gdb_size = 10, .gdb_offs = 214, FPU__(st_space[80]) }, [30] = { .gdb_size = 10, .gdb_offs = 224, FPU__(st_space[96]) }, [31] = { .gdb_size = 10, .gdb_offs = 234, FPU__(st_space[112]) }, [32] = { .gdb_size = 4, .gdb_offs = 244, FPU__(fctrl) }, [33] = { .gdb_size = 4, .gdb_offs = 248, FPU__(fstat) }, [34] = { .gdb_size = 4, .gdb_offs = 252, FPU__(ftag) }, [35] = { .gdb_size = 4, .gdb_offs = 256, FPU__(fiseg) }, [36] = { .gdb_size = 4, .gdb_offs = 260, FPU__(fioff) }, [37] = { .gdb_size = 4, .gdb_offs = 264, FPU__(foseg) }, [38] = { .gdb_size = 4, .gdb_offs = 268, FPU__(fooff) }, [39] = { .gdb_size = 4, .gdb_offs = 272, FPU__(fop) }, [40] = { .gdb_size = 16, .gdb_offs = 276, FPU__(xmm_space[0]) }, [41] = { .gdb_size = 16, .gdb_offs = 292, FPU__(xmm_space[16]) }, [42] = { .gdb_size = 16, .gdb_offs = 308, FPU__(xmm_space[32]) }, [43] = { .gdb_size = 16, .gdb_offs = 324, FPU__(xmm_space[48]) }, [44] = { .gdb_size = 16, .gdb_offs = 340, FPU__(xmm_space[64]) }, [45] = { .gdb_size = 16, .gdb_offs = 356, FPU__(xmm_space[80]) }, [46] = { .gdb_size = 16, .gdb_offs = 372, FPU__(xmm_space[96]) }, [47] = { .gdb_size = 16, .gdb_offs = 388, FPU__(xmm_space[112]) }, [48] = { .gdb_size = 16, .gdb_offs = 404, FPU__(xmm_space[128]) }, [49] = { .gdb_size = 16, .gdb_offs = 420, FPU__(xmm_space[144]) }, [50] = { .gdb_size = 16, .gdb_offs = 436, FPU__(xmm_space[160]) }, [51] = { .gdb_size = 16, .gdb_offs = 452, FPU__(xmm_space[176]) }, [52] = { .gdb_size = 16, .gdb_offs = 468, FPU__(xmm_space[192]) }, [53] = { .gdb_size = 16, .gdb_offs = 484, FPU__(xmm_space[208]) }, [54] = { .gdb_size = 16, .gdb_offs = 500, FPU__(xmm_space[224]) }, [55] = { .gdb_size = 16, .gdb_offs = 516, FPU__(xmm_space[240]) }, [56] = { .gdb_size = 4, .gdb_offs = 532, FPU__(mxcsr) }, [57] = { .gdb_size = 8, .gdb_offs = 536, GEN__(orig_ax) }, }; #undef FPU__ #undef GEN__ static inline int rw_one_reg(struct task_struct *task, int regnum, unsigned char regval[], bool write) { const struct user_regset_view *view; const struct user_regset *rset; struct gdbreg *gdbreg; int err, count; view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: if (regnum >= ARRAY_SIZE(gdb_regmap_64)) return -EINVAL; gdbreg = gdb_regmap_64; count = sizeof(long); break; default: return -EIO; } gdbreg += regnum; rset = view->regsets + gdbreg->rs_setno; if (gdbreg->rs_setno != REGSET_GENERAL) count = gdbreg->gdb_size; if (WARN_ON(count > MAX_REG_SIZE)) return -EOVERFLOW; if (write) err = rset->set(task, rset, gdbreg->usr_offs, count, regval, NULL); else err = rset->get(task, rset, gdbreg->usr_offs, count, regval, NULL); return err ?: gdbreg->gdb_size; } static int ugdb_rw_one_reg(struct ugdb *ugdb, int regnum, unsigned char regval[], bool write) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto ret; ret = rw_one_reg(task, regnum, regval, write); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; ret: return ret; } // XXX: hex_to_bin() after 90378889 commit #include static int cap_hex_to_bin(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - '0'; ch = tolower(ch); if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; return -1; } static int unhex(char *cmd, int size) { char *bytes = cmd; while (size--) { int lo, hi; hi = cap_hex_to_bin(*cmd++); lo = cap_hex_to_bin(*cmd++); if (lo < 0 || hi < 0) return -EINVAL; *bytes++ = (hi << 4) | lo; } return 0; } static const char *handle_set_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned int reg; int skip; if (sscanf(cmd, "P%x=%n", ®, &skip) != 1) goto err; cmd += skip; len -= skip; if (len & 1) goto err; len /= 2; if (unhex(cmd, len)) goto err; if (ugdb_rw_one_reg(ugdb, reg, cmd, true) != len) goto err; return "OK"; err: return "E01"; } static const char *handle_get_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned char regval[MAX_REG_SIZE]; unsigned int reg; int skip, size; if (sscanf(cmd, "p%x%n", ®, &skip) != 1) goto err; if (len != skip) goto err; size = ugdb_rw_one_reg(ugdb, reg, regval, false); if (size < 0) goto err; pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regval, size); pb_end(&ugdb->u_pbuf); return NULL; err: return "E01"; } static int rw_one_regset(struct task_struct *task, int rsn, const struct user_regset_view *view, void *reg_mem, int reg_size, struct gdbreg *reg_map, int reg_cnt, void *gdb_mem, bool write) { const struct user_regset *rset = view->regsets + rsn; int err; if (write) { for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(reg_mem + reg_map->usr_offs, gdb_mem + reg_map->gdb_offs, reg_map->gdb_size); } err = rset->set(task, rset, 0, reg_size, reg_mem, NULL); } else { err = rset->get(task, rset, 0, reg_size, reg_mem, NULL); if (err) goto ret; for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(gdb_mem + reg_map->gdb_offs, reg_mem + reg_map->usr_offs, reg_map->gdb_size); } } ret: return err; } #define GDB_REGS_SIZE(regmap) \ (regmap[ARRAY_SIZE(regmap)-1].gdb_size + \ regmap[ARRAY_SIZE(regmap)-1].gdb_offs) struct regs_buf { unsigned char gdb_mem[1024]; union { struct user_regs_struct user_regs_struct; struct user_i387_struct user_i387_struct; }; }; static int ugdb_rw_all_regs(struct task_struct *task, struct regs_buf *regs_buf, bool write) { const struct user_regset_view *view; int ret; #define RW(rsn, user, rmap) \ rw_one_regset(task, rsn, view, \ ®s_buf->user, sizeof(regs_buf->user), \ rmap, ARRAY_SIZE(rmap), regs_buf->gdb_mem, \ write) view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: // XXX: even this needs fixup. There is no ->fs_base in gdb's set // of regs, it is wrongly initialized as 0 and putreg()->do_arch_prctl() // changes fs. Later, gdb seems to never use G if P works. ret = RW(REGSET_GENERAL, user_regs_struct, gdb_regmap_64); if (ret) break; // XXX: needs fixup, see i387_fxsave_to_cache/i387_cache_to_fxsave. // At least xfpregs_get() is safe even if result is not correct. if (!write) ret = RW(REGSET_FP, user_i387_struct, gdb_regmap_64); if (ret) break; ret = GDB_REGS_SIZE(gdb_regmap_64); break; default: ret = -EIO; } #undef RW return ret; } static const char *handle_get_all_regs(struct ugdb *ugdb) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, false); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; if (size > sizeof(regs_buf->gdb_mem)) { WARN_ON(1); goto err; } if (pb_room(&ugdb->u_pbuf) < 3 + size * 2) { WARN_ON(1); goto err; } pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regs_buf->gdb_mem, size); pb_end(&ugdb->u_pbuf); ret = NULL; err: kfree(regs_buf); out: return ret; } static const char *handle_set_all_regs(struct ugdb *ugdb, char *cmd, int len) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; printk(KERN_INFO "XXX: $G command, why?\n"); cmd += 1; len -= 1; if (len & 1) goto out; len /= 2; if (unhex(cmd, len)) goto out; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; memcpy(regs_buf->gdb_mem, cmd, len); task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, true); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; WARN_ON(size != len); ret = "OK"; err: kfree(regs_buf); out: return ret; } static typeof(access_process_vm) *u_access_process_vm; static const char *handle_readmem(struct ugdb *ugdb, char *cmd) { struct utrace_examiner exam; struct task_struct *task; unsigned long addr, size; unsigned char *mbuf; int copied; if (sscanf(cmd, "m%lx,%lx", &addr, &size) != 2) goto err; size = min_t(unsigned long, size, pb_max_bs_size(&ugdb->u_pbuf)); if (!size) goto err; mbuf = pb_alloc_bs(&ugdb->u_pbuf, size); if (WARN_ON(!mbuf)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; copied = u_access_process_vm(task, addr, mbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (copied > 0 ) { pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, mbuf, copied); pb_end(&ugdb->u_pbuf); return NULL; } err: return "E01"; } static const char *handle_writemem(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; unsigned int skip, written; struct utrace_examiner exam; struct task_struct *task; if (sscanf(cmd, "M%lx,%lx:%n", &addr, &size, &skip) != 2) goto err; cmd += skip; len -= skip; if (len != 2*size || !size) goto err; if (unhex(cmd, size)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; written = u_access_process_vm(task, addr, cmd, size, 1); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (written == size) return "OK"; err: return "E01"; } static int ugdb_siginfo_rw(struct ugdb *ugdb, siginfo_t *info, bool write) { struct task_struct *task; struct utrace_examiner exam; struct sighand_struct *sighand; siginfo_t *t_siginfo; int ret = -EINVAL; /* * ugdb_prepare_examine() is overkill, but otherwise we can't * assume task_is_traced(), and this is what ensures we can * safely read/write ->t_siginfo which points to task's stack. */ task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto out; /* OK, task_struct can't go away, but ->sighand can. */ rcu_read_lock(); sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); if (!task_is_traced(task)) goto unlock_siglock; t_siginfo = ugdb->u_cur_hg->t_siginfo; if (!t_siginfo) goto unlock_siglock; if (write) *t_siginfo = *info; else *info = *t_siginfo; ret = 0; unlock_siglock: spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); ugdb_finish_examine(ugdb, &exam); out: return ret; } static const char *handle_siginfo_read(struct ugdb *ugdb, char *cmd) { unsigned int off, len; siginfo_t info; if (sscanf(cmd, "%x,%x", &off, &len) != 2) goto err; if (off >= sizeof(info)) goto err; if (len > sizeof(info) || off + len > sizeof(info)) len = sizeof(info) - off; if (ugdb_siginfo_rw(ugdb, &info, false)) goto err; if (pb_qfer(&ugdb->u_pbuf, &info + off, len, (off + len < sizeof(info)))) goto err; // XXX: Oh. we also need x86_siginfo_fixup(). how ugly. return NULL; err: return "E01"; } // ----------------------------------------------------------------------------- #define EQ(cmd, str) \ (strncmp((cmd), (str), sizeof(str)-1) ? false : \ ((cmd) += sizeof(str)-1, true)) static const char *handle_qfer(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; if (EQ(cmd, "siginfo:")) { if (EQ(cmd, "read::")) rc = handle_siginfo_read(ugdb, cmd); } return rc; } static void handle_command(struct ugdb *ugdb, char *cmd, int len) { struct pbuf *pb = &ugdb->u_pbuf; const char *rc = ""; switch (cmd[0]) { case '!': case '?': rc = "OK"; break; case 'H': rc = handle_set_cur(ugdb, cmd + 1); break; case 'T': rc = handle_ck_alive(ugdb, cmd + 1); break; case 'D': rc = handle_detach(ugdb, cmd + 1); break; case 'g': rc = handle_get_all_regs(ugdb); break; case 'G': rc = handle_set_all_regs(ugdb, cmd, len); break; case 'p': rc = handle_get_reg(ugdb, cmd, len); break; case 'P': rc = handle_set_reg(ugdb, cmd, len); break; case 'm': rc = handle_readmem(ugdb, cmd); break; case 'M': rc = handle_writemem(ugdb, cmd, len); break; case 'C': case 'c': case 'S': case 's': rc = handle_c(ugdb, cmd); break; case 'z': case 'Z': rc = handle_z(ugdb, cmd, len); break; case 'q': if (EQ(cmd, "qSupported")) { if (!strstr(cmd, "multiprocess+")) { printk(KERN_INFO "ugdb: can't work without multiprocess\n"); ugdb->u_err = -EPROTONOSUPPORT; } pb_packf(&ugdb->u_pbuf, "PacketSize=%x;%s", PACKET_SIZE, "QStartNoAckMode+;QNonStop+;multiprocess+;" "QPassSignals+;qXfer:siginfo:read+"); rc = NULL; } else if (EQ(cmd, "qfThreadInfo")) { rc = handle_thread_info(ugdb, true); } else if (EQ(cmd, "qsThreadInfo")) { rc = handle_thread_info(ugdb, false); } else if (EQ(cmd, "qXfer:")) { rc = handle_qfer(ugdb, cmd); } else if (EQ(cmd, "qTStatus")) { rc = "T0"; } break; case 'Q': if (EQ(cmd, "QStartNoAckMode")) { ugdb->u_no_ack = true; rc = "OK"; } else if (EQ(cmd, "QNonStop:")) { if (*cmd != '1') { printk(KERN_INFO "ugdb: all-stop is not implemented.\n"); ugdb->u_err = -EPROTONOSUPPORT; } rc = "OK"; } else if (EQ(cmd, "QPassSignals:")) { rc = handle_qpass_signals(ugdb, cmd); } break; case 'v': if (EQ(cmd, "vAttach;")) { rc = handle_vattach(ugdb, cmd); } else if (EQ(cmd, "vStopped")) { rc = handle_vstopped(ugdb); } else if (EQ(cmd, "vCont")) { rc = handle_vcont(ugdb, cmd); } break; default: ; } if (rc) pb_packs(pb, rc); } static void process_commands(struct ugdb *ugdb) { char *cmds = ugdb->u_cbuf; int todo = ugdb->u_clen; if (o_remote_debug) printk(KERN_INFO "=> %.*s\n", ugdb->u_clen, ugdb->u_cbuf); while (todo) { char first; char *c_cmd, *c_end; int c_len; first = *cmds++; todo--; switch (first) { default: printk(KERN_INFO "XXX: unknown chr %02x\n", first); pb_putc(&ugdb->u_pbuf, '-'); break; case '-': printk(KERN_INFO "XXX: got NACK!\n"); ugdb->u_err = -EPROTO; case '+': break; case 0x3: printk(KERN_INFO "XXX: unexpected CTRL-C\n"); break; case '$': c_cmd = cmds; c_end = strnchr(c_cmd, todo, '#'); c_len = c_end ? c_end - cmds : -1; if (c_len < 0 || todo < c_len + 3) { printk(KERN_INFO "XXX: can't find '#cs'\n"); ++todo; --cmds; goto out; } // XXX: verify checksum ? todo -= c_len + 3; cmds += c_len + 3; *c_end = 0; if (!ugdb->u_no_ack) pb_putc(&ugdb->u_pbuf, '+'); handle_command(ugdb, c_cmd, c_len); } } out: ugdb->u_clen = todo; if (todo && cmds > ugdb->u_cbuf) memmove(ugdb->u_cbuf, cmds, todo); } // ----------------------------------------------------------------------------- static int xxx_tinfo(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 0; mutex_lock(&ugdb->u_mutex); thread = ugdb_advance_tinfo(ugdb); if (thread) tid = thread->t_tid; mutex_unlock(&ugdb->u_mutex); return tid; } static int do_stop_thread(struct ugdb_thread *thread, void *arg) { ugdb_stop_thread(thread, arg != NULL); return 0; } static int do_cont_thread(struct ugdb_thread *thread, void *arg) { ugdb_cont_thread(thread, arg != NULL, false); return 0; } static int xxx_sc_threads(struct ugdb *ugdb, int tid, bool sc) { void *arg = NULL; int pid = 0; int ret; if (tid < 0) { pid = -tid; tid = -1; arg = (void*)1; } mutex_lock(&ugdb->u_mutex); ret = ugdb_do_each_thread(ugdb, pid, tid, sc ? do_stop_thread : do_cont_thread, arg); mutex_unlock(&ugdb->u_mutex); return ret; } static int xxx_stop(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, true); } static int xxx_cont(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, false); } static int xxx_get_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 1; if (ugdb->u_stop_state == U_STOP_IDLE) return -1; if (ugdb->u_stop_state == U_STOP_PENDING) tid = 1000; thread = ugdb_next_stopped(ugdb); if (!thread) return 0; return tid * thread->t_tid; } static int xxx_show_all(struct ugdb *ugdb) { struct ugdb_process *process; struct ugdb_thread *thread; printk(KERN_INFO "SHOW start ----------------------------------------\n"); mutex_lock(&ugdb->u_mutex); list_for_each_entry(process, &ugdb->u_processes, p_processes) { printk(KERN_INFO "PROC: %x\n", process->p_pid); list_for_each_entry(thread, &process->p_threads, t_threads) { printk(KERN_INFO " T: %x %p; %p %p\n", thread->t_tid, thread, thread->t_spid, pid_task(thread->t_spid, PIDTYPE_PID)); } } mutex_unlock(&ugdb->u_mutex); printk(KERN_INFO "SHOW end ----------------------------------------\n"); return 0; } static long ugdb_f_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ugdb *ugdb = file->private_data; // XXX: otherwise gdb->get_tty_state(TCGETS, TCSETS, TCFLSH) complains int ret = 0; // XXX: temporary debugging hooks, ignore. switch (cmd) { case 0x666 + 0: ret = ugdb_attach(ugdb, arg); break; case 0x666 + 1: ret = ugdb_detach(ugdb, arg); break; case 0x666 + 2: ret = xxx_tinfo(ugdb); break; case 0x666 + 3: ret = xxx_stop(ugdb, arg); break; case 0x666 + 4: ret = xxx_cont(ugdb, arg); break; case 0x666 + 5: ret = xxx_get_stopped(ugdb); break; case 0x666 + 6: ret = xxx_show_all(ugdb); break; } return ret; } static unsigned int ugdb_f_poll(struct file *file, poll_table *wait) { struct ugdb *ugdb = file->private_data; unsigned int mask; poll_wait(file, &ugdb->u_wait, wait); mask = (POLLOUT | POLLWRNORM); if (pb_size(&ugdb->u_pbuf) || ugdb->u_stop_state == U_STOP_PENDING) mask |= (POLLIN | POLLRDNORM); if (ugdb->u_err) mask |= POLLERR; return mask; } static ssize_t ugdb_f_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; struct pbuf *pb = &ugdb->u_pbuf; if (ugdb->u_err) return ugdb->u_err; if (ugdb->u_stop_state == U_STOP_PENDING) ugdb_report_stopped(ugdb, true); if (pb_size(pb) > count) { printk(KERN_INFO "XXX: short read %d %ld\n", pb_size(pb), count); } return pb_copy_to_user(pb, ubuf, count); } static ssize_t ugdb_f_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; if (ugdb->u_err) return ugdb->u_err; if (count > PACKET_SIZE - ugdb->u_clen) { count = PACKET_SIZE - ugdb->u_clen; printk("XXX: write(%ld,%d) enospc\n", count, ugdb->u_clen); if (1) return ugdb->u_err = -ENOSPC; } if (copy_from_user(ugdb->u_cbuf + ugdb->u_clen, ubuf, count)) return -EFAULT; ugdb->u_clen += count; process_commands(ugdb); return count; } static int ugdb_f_open(struct inode *inode, struct file *file) { nonseekable_open(inode, file); file->private_data = ugdb_create(); return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; } static int ugdb_f_release(struct inode *inode, struct file *file) { ugdb_destroy(file->private_data); return 0; } static const struct file_operations ugdb_f_ops = { .open = ugdb_f_open, .unlocked_ioctl = ugdb_f_ioctl, .poll = ugdb_f_poll, .read = ugdb_f_read, .write = ugdb_f_write, .release = ugdb_f_release, }; #include struct kallsyms_sym { const char *name; unsigned long addr; }; static int kallsyms_on_each_symbol_cb(void *data, const char *name, struct module *mod, unsigned long addr) { struct kallsyms_sym *sym = data; if (strcmp(name, sym->name)) return 0; sym->addr = addr; return 1; } // XXX: kallsyms_lookup_name() is not exported in 2.6.32 static bool lookup_unexported(void) { struct kallsyms_sym sym; sym.name = "access_process_vm"; if (!kallsyms_on_each_symbol(kallsyms_on_each_symbol_cb, &sym)) goto err; u_access_process_vm = (void*)sym.addr; return true; err: printk(KERN_ERR "ugdb: can't lookup %s\n", sym.name); return false; } #define PROC_NAME "ugdb" struct proc_dir_entry *ugdb_pde; static int __init ugdb_init(void) { if (!lookup_unexported()) return -ESRCH; ugdb_pde = proc_create(PROC_NAME, S_IFREG|S_IRUGO|S_IWUGO, NULL, &ugdb_f_ops); if (!ugdb_pde) return -EBADF; return 0; } static void __exit ugdb_exit(void) { remove_proc_entry(PROC_NAME, NULL); } MODULE_LICENSE("GPL"); module_init(ugdb_init); module_exit(ugdb_exit); From objectize at sembikiya.co.jp Mon Oct 18 20:09:20 2010 From: objectize at sembikiya.co.jp (Thalmann Limauro) Date: Mon, 18 Oct 2010 22:09:20 +0200 Subject: ampled pr Message-ID: <1287432037-exsanguine@sembikiya.co.jp> A non-text attachment was scrubbed... Name: evolute.png Type: image/png Size: 21350 bytes Desc: not available URL: From mkt at refrimur.com Tue Oct 19 03:50:17 2010 From: mkt at refrimur.com (Refrimur) Date: Tue, 19 Oct 2010 01:50:17 -0200 Subject: Campanha Outubro (II) REFRIMUR 2010 Message-ID: <75cc1b904b420e19c3cbf1394e0ca959@refrimur.com>   Problemas para visualizar a mensagem? Acesse aqui   Clique para não receber nossos emails     -------------- next part -------------- An HTML attachment was scrubbed... URL: From johnson at dsl51B7D112.fixip.t-online.hu Tue Oct 19 04:04:27 2010 From: johnson at dsl51B7D112.fixip.t-online.hu (deposit Bishop) Date: 19 Oct 2010 06:04:27 +0200 Subject: Healthcare, Business and Finance mailing/email lists Message-ID: Package deals this week: 5 lists for $300 or 1 for $149 (Offer ends Friday) *Inquire about custom packages also available for other quantities* You can choose any list from the catalog below: [ HEALTHCARE ] > Complete US Physicians Database > Chiropractic Doctors in the USA > American Holistic Medicine Providers/Clinics > General Dentists in the USA > American Veterinarians & Veterinary Clinics > US Hospitals > Nursing Homes int the US > Pharmaceutical Company Employees > Physical/Occupational Therapy Clinics and Therapists in the US > Oncology Physicians in the US > US Surgery Centers > Massage Therapists/Therapy Clinics in America > Acupuncturists/clinics in the US > Medical Equipment Suppliers(USA) > Mental Health Counselors (USA) > Optometrists/Clinics (USA) > Psychologists (USA) [ BUSINESS LISTS ] > Hotels in the USA > Realtors in the USA > USA Business Database > Manufacturer Database (USA) > Financial Planner Database (USA) > Finance & Professionals Database (USA) [ CONSUMER LISTS ] > USA Consumer Database > Credit Inquiries Database (USA) > American Homeowners [ PROFESSIONALS LISTS ] > USA Lawyers Database > Criminal Attorneys in the US Email me for counts, breakdowns and sample spreadsheets: thinksuccess at gmx.com to stop this email in future email us at purgefile at gmx.com From bno at bweg.com Tue Oct 19 15:17:33 2010 From: bno at bweg.com (=?GB2312?B?x+vXqsjLysI=?=) Date: Tue, 19 Oct 2010 15:17:33 -0000 Subject: =?GB2312?B?dXRyYWNlLWRldmVstNO8vMr119/P8rncwO0=?= Message-ID: <201010191517.o9JFH1S0002733@mx1.redhat.com> utrace-devel??????? ?????2010?10?25-26? ?? ?????2010?10?28-29? ?? ?????2010?11?25-26? ?? ?????2010?12?30-31? ?? ?????3200?/?? ????(?????????????????????) ???????????2200??????* ?????????????????? ????????????????????????????? ???????CEO/?????????/???????/???????????/???????? ???????????PMO???????????????????????? ?????020-80560638?020-85917945 ???????????????chinammc2010 at 126.com??? ---------------------------------------------------------------------------------- ???? 1.??????????????????????????????????????? 2.???????????????????????? 3.??????????????????????? 4.????????????????????????????????????????? 5.???????????? 6.??????????????????????????????????????????????????? 7.?????????????????????? 8.???????????????????????????????????????? Action Plan? ???????????????????? ------------------------------------------------------------------------------------- ???? ???????0.5? 1)???????????? ????????????????????1.5? 1)?????????????????? 2)?????????????? 3)?????????????? ???????????????????? ???????10????? ???????????????????????? ????????? 4)?????????????????????????????????????????????????? ???????????????????????????? 5)???????????? 6)??????? 7)?????????????? ??????????????? ???????? ???????????? ???????????????? ?????????? ???????????? ?????????????? ?????????????? ??????????????????? ????????????? 8??????????????????????? 9???????? ????????????????3.5? 1)???????? 2)????? 3)????????? ???????? ???????????? ?????????????? ????????????? ????????????????????????? ????????????????????????????? 4)????????? ???????????????? ?????????????????????????? ?????????????????????? ????????????????????? ????????? ????????? ??????????????????? ??????????????????? ??????????????????????? ??????????????????????????????? ??????????????????????????????????????????? ???????????????????? 5)????????? ????????????????? ?????????????????????? ?????????????????????????????????? ?????????????????????????????????????? ??????????????? 6)????????? ???????????? ??????????? ???????????? ??????????????????? 7)????????? ??? ?????????????? ???????5??? ????????????????? ????????????????? ??????? ?????????????QA???? ?????????? ?????????? ?????????????????QA??????? ??????????????????????? ???????????????1.5? 1)????????????????????????? 2)????????????????????????????? 3)????????? 4)????????????? 5)??????? 6)????????????? 7)?????????????????????? 8)???????? 9)??????????? 10)?????????????? 11)??????????? 12)?????????? 13)????????????? 14)???????????????? 15)?????????????????????????????????????????? 16)????????? 17)???????????????????? 18)????????? 19)?????????????????????? ???????????????????????????1.0? 1)???????? 2)???????????? 3)????????????????????????? 4)????????????????? 5)???????????? 6)?????????SMART??????????????PBC?? 7)?????????????SMART 8)?????????SMART???????????SMART 9)???????PDCA?? 10)????????????????????????????????? 11)?????????? 12)??????????? 13)PERT??????GANNT 14)???????????PERT? 15)?????????????????????????????? 16)???????????? 17)????????? 18)???????????? 19)??????????????????? ?????????????????????????????2.0? 1)???????????? 2)??????????? 3)???????????? 4)???????????? 5)????????????????? 6)????????? 7)???????? 8)???????? 9)???????/???? 10)??????????? 11)????????????? 12)???????????? 13)????????????????????????? 14)????????????????????????????? 15)??????????????????????????????????????????????????? ????????????????????? 16)??????????????????????????????? 17)???? 30 ?????????????????????????????????????????????? ?????????????? 18)?????????????????????????????????? 19)????????????????????????????????? 20)????????????????????????????? 21)??????????????????????? 22)??????????????????? ?? ?????????????????????????1.5? 1)??????????? 2)?????????????? 3)????????? 4)?????????????????????? 5)???????????????????????? 6)?????????????????????? 7)??????????????????????????? 8)???????????????????????? 9)?????????????????????????? 10)?????????????????????? 11)????????????????????????? 12)??????????????????????PCB? 13)????????????????? ???? ???????????????? ???????????????????????? ?????????????????? ?????????? ??????????????????????????????? 14)?????????????? 15)???????????? 16)??????????????????? 17)?????????? 18)??????????????????? 19)???????????????? 20)???????????? 21)??????????????????? 22)????????????????????????? 23)??????? ???????????????????????????2.0? 1)?????????? 2)???????????? 3)?????????????????????? 4)?????????????????? 5)???????? 6)???????????????? 7)???????????????? 8)???????????????????????? ????????? ????????????????????? ??????????KPI????????????? ?????????BSC?????????? ????????PBC????????????? ?????360????????????? ????? ???????????????? ??????????????????? ???????????????? 9)????????????????? ??????????????? ????????7??????????????????????????????????????????????????????? ????????????????????????????????????????????????? ????????????????????? ??????????????????????QA?????????????????? 10)???????????????????? ?????????? ???????????????????? ????????????????????? ?????????????????????? ?????????????????????????????????????????????? ?????????????????? ?????????????????? ?????????????????????? ??????????????????????????? ????????????????????????????????????????????? ??????????????? ?????????????????????????? 11)????? ???????????????????0.5? 1)????????? 2)??????? 3)????????????????? 4)??????????? ????????????????????? -------------------------------------------------------------------------------------------- ???? ??? ???? ?????10?????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ?????IPD??????ITS&P?????IPD????????????????????????? ???IPD????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ????????????????????????????????????????????? ??????????????????????????????????????????????? ?????????????????????????????????????10????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ??????????????????????????????????????????????? ????????????????? ----------------------------------------------------------------------------------------- ??????????????????020-62351156? ???????? ??? ??? ??? ??? ? ? ? ??_______________________________________________________ ????______________??:________________??:________________ ???______________ ? ? ? ?:_________? ? ? ??_________? ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ? ? ??___________? ? ? ??____________? ? ? ??_____________ ?????????????? ?1??? ?2??? ?3??? ==================================================================================== ??:????????????????????,???????020-80560638??? From mldireto at tudoemoferta.com.br Mon Oct 18 22:10:42 2010 From: mldireto at tudoemoferta.com.br (TudoemOferta.com) Date: Mon, 18 Oct 2010 20:10:42 -0200 Subject: Bricolagem e Jardinagem - 30% de Desconto - Sua Vontade, Nossas Ferramentas Message-ID: <03014e1c928afce29a892683d574114a@www.tudoemoferta.com> Para visualizar esta mensagem, utilize o modo de leitura em HTML. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Tue Oct 19 19:47:12 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Tue, 19 Oct 2010 21:47:12 +0200 Subject: utrace && unwanted traps In-Reply-To: <20101014234618.5088940096@magilla.sf.frob.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926160103.GB20803@redhat.com> <20101014234618.5088940096@magilla.sf.frob.com> Message-ID: <20101019194712.GA14945@redhat.com> On 10/14, Roland McGrath wrote: > > > In short: I no longer understand why utrace->resume can be UTRACE_*STEP > > when the tracee is stopped, and in fact I think this is not right. > > I think we didn't have that originally. Yes. > The rationale that I remember is > the idea that you should be able to implement a debugger interface feature > like PTRACE_SINGLESTEP without noticeably more overhead than it had in > pre-utrace ptrace. That is, in vanilla ptrace, the tracer thread calls > user_enable_single_step itself and then just lets the tracee resume > directly to user mode. We wanted to avoid always having an additional trip > through tracehook_notify_resume and the utrace reporting loop and then back > through the return-to-user assembly path a second time, between the tracee > waking up and actually going to user mode. Probably, I am not sure. I can't recall the previous discussions. IIRC, the main problem with user_enable_single_step() was: we wanted to move the callsite from tracer to tracee by many reasons. I can't recall if "avoid another reporting loop" was the target, and additional trip through tracehook_notify_resume() is not avoidable anyway. Afaics, this was introduced by 26fefca955cc7c3c83014be2e10b773209d32eea "utrace: sticky resume action". Before that patch the stopped tracee could only "remember" the pending UTRACE_REPORT or UTRACE_INTERRUPT. > Right. Said another way, any time an engine that previously used > UTRACE_*STEP now uses UTRACE_RESUME, we must degrade utrace->resume back to > UTRACE_REPORT at most. Since we don't keep track of which engine it was > that put UTRACE_*STEP into utrace->resume before, we'd have to just always > degrade it any time anybody uses UTRACE_RESUME. Agreed. > That has almost the whole effect of punting utrace->resume back to just a > utrace->report flag. (see below) > But that's how it used to be, and then we changed it. > So it merits digging up our old discussion threads that led to doing that > and see what all we had in mind then. I tried to grep my mail archives and google, but failed to find anything related. _Perhaps_ this was not intended actually. Before the commit above, another problem was fixed by 8ad60bbd4c665a11be179a0bff41483cca3b3560 "utrace_stop: preserve report/interrupt requests across stop/resume", until this one it was possible to lose UTRACE_INTERRUPT request if it "races" with UTRACE_STOP from another engine. So, perhaps cleanup was the main reason for 26fefca9. See also http://www.mail-archive.com/utrace-devel at redhat.com/msg01647.html Oleg. From td at cm.com Tue Oct 19 21:49:34 2010 From: td at cm.com (=?GB2312?B?x+vXqs/gudjIy9Sx?=) Date: Tue, 19 Oct 2010 21:49:34 -0000 Subject: =?GB2312?B?dXRyYWNlLWRldmVs16jStcPYyunQ0NX+yMvUsby8xNzM4cn9?= Message-ID: <201010192149.o9JLnCtP010697@mx1.redhat.com> utrace-devel???????????????????????????????? ????: 2010??10??23-24?? ?????????? ??????2010??10??30-31?? ?????????? ??????????2500/???????????????????????????????????? ?????????????????????????????????????????????????????????????? ??????????020-80560638??020-85917945 ????????????????????????????chinammc2010 at 126.com?????? ======================================================================================== ???????????????????? 1.?????????????????????????????????????????????????????????????????????? 2.???????????????????????????????????????? 3.???????????????????????????????????????????? 4.?????????????????????????????????????????????????????????????? 5.?????????????????????????????????????????????? 6.?????????????????????????? 7.?????????????????????????????????????????? 8.???????????????????????????????????????????????????????? 9.???????????????????????????????????????????? 10.???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????? ?????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????? ?????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????? ?????????? ???????????????????????????????????????????? ?????????????????????????????????????????????? ???????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????? =========================================================================================== ????????: ???????? ????/?????????????? 1.????/???????? 2.????????/???????????????? 3.????????/?????????????????????????? 4.????????/???????????????????????? 5.???????????????????????D?D?????????????????? 6.???????????????????????????? 7.?????????????????????????????????????????? 8.????/?????????????????? 9.???????????????????????????????????????????? ???????? ????????/?????????????? 1.????/?????????????????D?D????????????????/????/???????? 2.?????????????????????? 3.?????????????????????????????????????????????????? 4.????????????????????PDP??????NLP???? 5.????????????????????????????5W1H?????????? 6.?????????????????????????? 7.???????????????? 8.???????????????????????????????????????????????????????????????? ???????? ????????5S???? 1.5S?????? 2.???????????????????????? 3.???????????????????????? 4.???????????????????????? 5.???????????????????????? 6.???????????????????????????? ???????????????? 1.??????????5?????? 2.???????????????????????????? 3.?????????????????? 4.???????????????????????????????? 5.???????????????????????????????????????????????????????? 6.?????????????????????????????????????????????? 7.?????????????????????????? ?????????????????????????? 1.???????????????????????????? 2.PDCA?????????????????????????? 3.????SMAC???????????????????? 4.??????????/????/?????????????????????? 5.???????????????????????????????????????????????????????? ?????????????????????????????????? 1.?????????????? 2.?????????????? 3.?????????????????????????????????? 4.?????????????????? 5.????????????????????12?????? 6.?????????????????? 7.???????? 8.???????????????????????????????? ???????????????? 1.???????????????? 2.?????????????????? 3.?????????????????? 4.?????????????????? 5.?????????????????? 6.?????????????????? 7.?????????????????? ?????????????????????????????? 1.???????? 2.?????????? 3.?????????????????? ???????????????????? 1.?????????????????????????????? 2.?????????????? ???????????????????????????????????????????????????????????????? ??????????????????????????????/????/?????????????????????????????????????? 3.?????????????????????????????? ?????????????????????????????????????????????? ========================================================================================== ???????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????5????????????500?????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????????????????????TTT???????????????? ??????????????????????????/???????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????????????????????????????????????????TCL?? ???????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????? =========================================================================================== ??????????/????????????????????????????????????????????????????020-62351156?? ?? ?? ?? ?? ?? ????_______________________________________________________ ?? ?? ?? ???? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________ ?? ?? ?? ??:_________?? ?? ?? ????_________?? ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ???????????????????????????? ??1?????? ??2?????? ??3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From h6a442721 at aim.com Tue Oct 19 22:18:16 2010 From: h6a442721 at aim.com (sogihome) Date: Tue, 19 Oct 2010 18:18:16 -0400 Subject: =?utf-8?Q?=E4=BA=9E=E5=A4=AA=E9=9B=BB=E4=BF=A1=E8=AE=93=E4=BD=A0=E7=9C=81?= =?utf-8?Q?=E6=9B=B4=E5=A4=9A_=E8=B6=85=E5=84=AA=E9=9B=99=E5=8D=A1=E6=A9?= =?utf-8?Q?=9F!wjm0t5c7c?= Message-ID: <8CD3DF2A969D35F-1EC4-1988@webmail-m067.sysops.aol.com> bb -------------- next part -------------- An HTML attachment was scrubbed... URL: From zdi at cyhd.com Tue Oct 19 22:58:10 2010 From: zdi at cyhd.com (=?GB2312?B?x+vXqs/gudjIy9Sx?=) Date: Wed, 20 Oct 2010 06:58:10 +0800 Subject: =?GB2312?B?dXRyYWNlLWRldmVs0dC3os/uxL+53MDtuaS+39PrxKOw5Q==?= Message-ID: <201010192258.o9JMvfj7015482@mx1.redhat.com> utrace-devel?????????????????????? ??????????2010??10??25-26?? ???? ??????????2010??10??28-29?? ???? ??????????2010??11??29-30?? ???? ??????????2010??12??27-28?? ???? ??????????3200??/???? *????????,?????????? (?????????????????????????????????????????? ??????1??????????????????2200??/?????????????????????????????????????????? ?????????????????????????????????????????????????????????? ????????????????????/??????????????/??????????????????????/??????????PMO??????????????????????QA???? ??????????020-80560638??020-85917945 ??????????????????????????????chinammc2010 at 126.com?????? ---------------------------------------------------------------------------------- ???????? 1.???????????????????????????????????????????????????????????? 2.???????????????????????????????????? 3.?????????????????????????????????? 4.?????????????????????????????????????????????????????????? 5.?????????????????????????? 6.?????????????????????????????? 7.???????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 8.???????????????????????????????????????????????????????????? ------------------------------------------------------------------------------------------------ ???????? ???????????? 1.?????????????????????? 2.?????????????????????????????????????????????????????????????? 3.?????????????????????????????????? 4.?????????????????????????????????????? ???????????????????? 1.?????????????? 1)?????????????????????? 2)?????????????????????? 3)?????????????? 4)??????????????????????????????????(PMI) 2.???????????? 1)?????????????????? 2)?????????????????????????? 3)???????????????????????????? 3.??????????????V??R??M???????? 1)?????????????? 2)?????????????? 3)?????????????? 4.???????????????????? 1)???????????????????????????????????????????? 2)?????????????????????????? 5.?????????????? 6.???????????????????? 1)?????????????????????D?D???????????????????????????????? 2)???????????????????? ?????????????????????? 1.?????????????????????? 1)?????????? 2)?????????? 3)?????????? 2.???????????????????????????? 1)???????????????????????? 2)?????????????????????????????? 3)?????????????????????????????? 4)?????????????????????????????????????? 3.???????????????????????? 1)???????????????????????????????? 2)?????????????????????????? 4.?????????????? 5.???????????????????? 1)???????????????????????????????????????????????????? 2)???????????????????????????????????? 3)?????????????????????? 4)?????????????????????????????????????????????????? 5)???????????????????????????? ???????????????????? 1.?????????????????????????????????? 1)?????????????????????????? 2)?????????????????????????????????? 3)?????????????????????????????????????? 2.????????????IT?????? 1)???????????????????????????? 2)????????3?????????? ??????????????????????????????? ??????????? ??????????? ??????????????????? ????????????????????????????????? 3)?????????????????????????????? 4)?????????????????????????? 5)?????????????????????????????? 3.?????????????????????????? 1)?????????????????????????? 2)???????????????????????????????????????? 3)???????????????????? 4.?????????????????????????????? 1)?????????????????????????? 2)???????????????????????????????????????? 3)?????????????????????????? ????????????????????? ????????????????????????????????????????????? ????????????????????????????????????????????? 5.???????????????????????????? 1)WBS?????????????????? 2)WBS?????????????? 3)PBS??WBS??OBS??CBS?????????????? 4)?????????????????? 5)?????????????????????? ? *?????????????????????????? ?*???????????????????????????? ?*???????????????????????????? 6)???????????????????? ?*?????????? ?*?????????? 6.???????????????????????????????????? 1)?????????????????????????? 2)?????????????????????????? 7.?????????????????????????? ???? ?????? 1)?????????????? 2)???????????????????? 3)???????????????????????? 4)???? 8.???????????????????? 1)?????????????????????????????? 2)???????????????? 3)???????????????????????? 4)??????????????????????PCB?????????????????????????? 5)???????????????????????????? 9.?????????????? ???????????????????? 1.???????????????? 1)?????????????????? 2)???????????????????????? 3)???????????????????? ?*???????? ?*?????? ?*?????? 2.?????????????????????????? 1??.?????????????????????????????????????????????????????????? 2??.?????????? 3??.?????????? 4??.?????????? 5??.???????? 6??.?????????? 7??.????????????(PCB) ?????????????????????????? 3.?????????????????????????? 1??.???????????????? 2??.???????????????? 3??.?????????????? 4??.???????????????? 5??.?????????????????? 6??.?????????????????? ?.?????????????? ? .???????????? ? .?????????????????? ? .???? 4.?????????????????????????? 1??.???????? ? .???????? ? .???????? ? .???????? 2??.?????????????????????????? 3??.???????????????????????? 4??.???????????????? ? .?????????????? ? .???????????????????? 5??.?????????????? 5.???????????? ? .QA?????????? ?.QA???????? ? .QA?????????? ? .????????????????QA?? 6.?????????????????? 1??.???????????????????????? 2??.?????????????????????? 3??.???????????????????? 4??.???????????????? 5??.?????????????????????? 6??.?????????????????????? 7??.???????????????????????? 8??.???????????????????????????????? 9??.???????????????????????????????? 10??.???????????????????????????????? 11??.???????????????????????????????? 12??.???????????????????????????????? 13??.???????????????????????????????? 14??.???????????????????????? 15??.???????????????????????????????? 16??.???????????????????????????????? 17??.???????????????????????????????? 18??.???????????????????????????????? 19??.???????????????????????????????? 20??.???????????????????????????????? 21??.???????????????????????????????? ???????????????????? 1.?????????????????????????????????????? 2.???????????????????????? 3.???????????????????????? 1)?????????????? 2)???????????? 3)?????????????????? 4)?????????????????????????? 5)?????????????????? 4.?????????????????????????? 1)???????????????????????? 2)???????????????????? 3)???????????????????? 4)???????????????????????????? 5.?????????????????????????? 1)???????????? 2)???????????? 6.?????????????????????????? 1)???????????? 2)?????????????? 7.?????????????????????????????? 1)???????????? 2)???????????? 8.???????????????? 1)???????? 2)???????????? 3)?????????????? 4)???????? 5)???????? 6)QA???????? 9.?????????????? 1)?????????????????????????????????????????????????????????????????????? 2)???????????????????????? 3)???????????????????????? 10.?????????????? 1)?????????????????????????????????????????????? 2)???????????????????????????????????????? 3)?????????????????????????????????????????? 4)???????? 5)???????????????????????????? 6)?????????????????????????? 7)?????????????? 11.?????????????????????????????????????????????????? 1)?????????????? 2)?????????????????????????????????? 3)?????????????????????????? 4)???????????????????????????????? 12.?????????????? 13.???????????????????? 1)???????????????? 2)????????/???????????? 3)???????????????? 4)???????????????? 5)???????????????????????? 6)??SEI?????????????? 7)???????????????????? 8)?????????????????????? ?????????????????????? 1.???????????????????????????????? 2.???????????????????????????? 3.???????????????????? 4.???????????????????????????? 5.?????????????????????????????????????? ----------------------------------------------------------------- ?????????????? ???????????????? CMM/CMMI???????? ?????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????? ??????????????????????NGN???????????????? ?????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????????????????????????CMM???????? ???????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????????????????????????????????????(????????) ?????????????????????????????????????????????????????????????????????????????????????? CMMIL4????????CMMI L2?????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????? ????????????????????????????????????????????020-62351156?? ?????????? ?????? ?????? ?????? ?????? ?? ?? ?? ????_______________________________________________________ ????????______________????:________________????:________________ ??????______________ ?? ?? ?? ??:_________?? ?? ?? ????_________?? ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ???????????????????????????? ??1?????? ??2?????? ??3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638?????? From roland at redhat.com Wed Oct 20 00:16:00 2010 From: roland at redhat.com (Roland McGrath) Date: Tue, 19 Oct 2010 17:16:00 -0700 (PDT) Subject: utrace && unwanted traps In-Reply-To: Oleg Nesterov's message of Tuesday, 19 October 2010 21:47:12 +0200 <20101019194712.GA14945@redhat.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926160103.GB20803@redhat.com> <20101014234618.5088940096@magilla.sf.frob.com> <20101019194712.GA14945@redhat.com> Message-ID: <20101020001600.DE891401C7@magilla.sf.frob.com> > Probably, I am not sure. I can't recall the previous discussions. Me either (except hazily the one notion I mentioned), but that's why we have mailing list archives. > Afaics, this was introduced by 26fefca955cc7c3c83014be2e10b773209d32eea > "utrace: sticky resume action". Before that patch the stopped tracee > could only "remember" the pending UTRACE_REPORT or UTRACE_INTERRUPT. Correct. > > But that's how it used to be, and then we changed it. > > So it merits digging up our old discussion threads that led to doing that > > and see what all we had in mind then. > > I tried to grep my mail archives and google, but failed to find anything > related. Based on the date of the commit you just mentioned, I browsed in: https://www.redhat.com/archives/utrace-devel/2009-October/thread.html and saw: https://www.redhat.com/archives/utrace-devel/2009-October/msg00287.html which is the day before that commit. I didn't read through all that to refamiliarize myself with all the details. Thanks, Roland From roland at redhat.com Wed Oct 20 00:32:00 2010 From: roland at redhat.com (Roland McGrath) Date: Tue, 19 Oct 2010 17:32:00 -0700 (PDT) Subject: [PATCH] utrace: utrace_resume()->start_callback() must clear ->reporting In-Reply-To: Oleg Nesterov's message of Tuesday, 12 October 2010 21:42:05 +0200 <20101012194205.GA22939@redhat.com> References: <20100818181147.GA4995@redhat.com> <20101011180442.GA17725@redhat.com> <20101011214707.A992D401B4@magilla.sf.frob.com> <20101012194205.GA22939@redhat.com> Message-ID: <20101020003200.33ACA401C7@magilla.sf.frob.com> I've merged this and also put it on the 2.6.32, 2.6.34, and 2.6.35 backport branches. The trunk is now also merged up from v2.6.36-rc8. Thanks, Roland From roland at redhat.com Wed Oct 20 00:54:44 2010 From: roland at redhat.com (Roland McGrath) Date: Tue, 19 Oct 2010 17:54:44 -0700 (PDT) Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: Oleg Nesterov's message of Friday, 15 October 2010 15:52:58 +0200 <20101015135258.GA4534@redhat.com> References: <20100818172704.GA2230@redhat.com> <20101013065538.63094401B2@magilla.sf.frob.com> <20101015135258.GA4534@redhat.com> Message-ID: <20101020005444.D00D1401C7@magilla.sf.frob.com> > Yes. But, with this patch, in this case > utrace_barrier()->get_utrace_lock(attached => false) returns success > and then we check utrace->reporting == engine. I guess that's OK if ->reporting == engine is always set when any kind of callback might be in progress. > (Hmm. Probably utrace->reap = T case needs more attention, > utrace_maybe_reap() doesn't set utrace->reporting). That would be a problem. > But, unfortunately, this signal_pending() check assumes the caller can > always handle this ERESTARTSYS. But this is not true, one example is > the exiting debugger doing exit_ptrace(). I understand it's a problem. Perhaps we need to have a flag argument or (probably better) a new utrace_barrier_uninterruptible call. But, for this particular situation with exit_ptrace, it could be kludged around. The caller is never going to dequeue another signal once it's as far into death as exit_ptrace anyway. So, it could do a loop of: ret = utrace_barrier(task, engine); if (ret == -ERESTARTSYS) { clear_thread_flag(TIF_SIGPENDING); continue; } Not that I'm suggesting this isn't a dismal kludge. But it seems like it would close the hole we have today in practice. Thanks, Roland From marketing at masterplugin.com.br Wed Oct 20 00:30:21 2010 From: marketing at masterplugin.com.br (masterweb) Date: Tue, 19 Oct 2010 20:30:21 -0400 Subject: =?UTF-8?B?UmVsw7NnaW8gZXNwacOjbyBmaWxtYSBhdMOpIDkgaG9yYXM=?= Message-ID: <859f89e016c326a292262cb233f96808@189.1.164.117> An HTML attachment was scrubbed... URL: From vendas at masterwebinfo.com.br Wed Oct 20 00:34:59 2010 From: vendas at masterwebinfo.com.br (masterweb) Date: Tue, 19 Oct 2010 20:34:59 -0400 Subject: =?UTF-8?B?RGl2dWxndWUgc2V1cyBwcm9kdXRvcyBlIHNlcnZpw6dvcyAweHgxMSAyMDE3LTA3Mjk=?= Message-ID: <919b1eca9eb00a48a0dcfecf0baf673f@189.1.164.117> An HTML attachment was scrubbed... URL: From feedback at isketchfz.com Wed Oct 20 08:24:53 2010 From: feedback at isketchfz.com (Mr. Kevin Brown) Date: Wed, 20 Oct 2010 01:24:53 -0700 (MST) Subject: =?utf-8?Q?=C4=8Cesk=C3=A1_republika?= Message-ID: <18182562.137317.1287563093769.JavaMail.root@mail4a.brinkster.com> Dobr? den, p??teli, J? jsem pan Kevin Brown mana?er ??etnictv? / Audit ministerstva NatWest banky Harlsden, North West London, Anglie. Kontaktoval jsem si, co se t?k? podnik?n? n?vrh, kter? bude m?t obrovsk? p??nos pro n?s oba a m?n? privilegovan? ty. B?t mana?erem ??etn?ho / auditu Greater London Krajsk? ??ad jsem zjistil, sou?et ? 15,000,000.00 GBP (patn?ct milion? britsk?ch liber ?terlink?) na ??tu, kter? pat?? k jednomu z na?ich zahrani?n?ch z?kazn?k? Pozdn? Pan Moises Saba Masr?ho. On byl ?idovsk? obchodn? magn?t z Mexika, kter? zem?el v z??cen? vrtuln?ku na za??tku leto?n?ho roku. Pan Saba byl 47-roky-star?, kdy? ob? jeho man?elky, jeho jedin? syn Avraham (Albert) a jeho dcera-v-pr?vo zem?el v z??cen? vrtuln?ku. M??ete z?skat v?ce informac?, pokud jde o p?d a smrt na?eho pozd? z?kazn?ka pana Moj???e Saba na adresu webov?ch str?nk?ch n??e: http://www.ynetnews.com/articles/0,7340,L-3832556,00.html Volba V?s kontaktovat vzbudil z geografick? povahy, kde ?ijete, zejm?na vzhledem k citlivosti na transakce a d?v?rnost zde. Nyn? n?? bankovn? bylo ?ek?n? na n?kter? z p??buzn?ch p?ijde-a? k tvrzen?, d?dictv? fondu, ale bohu?el ve?ker? ?sil? m? b?t neplatn?. J? osobn? jsem byl ne?sp??n? p?i rozmis?ov?n? p??buzn?m ani nejbli???m p??buzn?m pana Saba. Na tomto jde, m?m usilovat o v?? souhlas k v?m jako dal?? p??buzn? / bude p??jemce na zem?el?ho tak, ?e v?t??ek z tohoto ??tu ocen?n na ? 15 milion? britsk?ch libr?ch b?t vyplacena na v?s. To bude vyplacena, nebo sd?len? v t?chto procent 60% pro m? a 40% na v?s. M?m zaji?t?n? ve?ker? nezbytn? pr?vn? dokumenty, kter? mohou b?t pou?ity k z?lohov?n? toto tvrzen? se chyst?me d?lat. V?e, co pot?ebujete, je nahr?t va?e jm?na na dokumenty a legalizovat u britsk?ho Nejvy???ho soudu za ??elem prok?z?n? v?s opr?vn?n? p??jemce. V?echny ??d?m nyn? je va?e up??mn? Co-operace, d?v?rnosti a d?v?ry k tomu, aby n?s vid?t tuto transakci prost?ednictv?m. J? v?m zaru?it 100% ?sp??nost a ?e tato obchodn? transakce budou provedeny v r?mci p?sobnosti pr?va a tak? chr?nit v?s z jak?hokoli poru?en? smlouvy. Uve?te, pros?m, mi n?sleduj?c?, jak jsme 7 pracovn?ch dn? spust?me ji proj?t: 1. Va?e cel? jm?no 2. Telefonn? ??slo 3. Kontaktn? adresa 4. V?k 5. Pohlav? 6. Povol?n? S pro?la metodick? vyhled?v?n?, rozhodl jsem se V?s kontaktovat doufat, ?e v?s najdou tento n?vrh zaj?mav?. Pros?m o Va?e potvrzen? t?to zpr?vy a nazna?uje v?? z?jem budu v?m poskytne bli??? informace je. V?? souhlas s t?mto e-mailu a obchodn? n?vrh bude vysoce ocenil. S pozdravem, Pan Kevin Brown ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... From mldireto at tudoemoferta.com.br Mon Oct 18 18:47:54 2010 From: mldireto at tudoemoferta.com.br (Carlos Nogueira - Corporativo ArtShop) Date: Mon, 18 Oct 2010 16:47:54 -0200 Subject: Especial Dia das Criancas - 30% de desconto c/ Entrega Nivel Brasil - Porta a Porta. Message-ID: Para visualizar esta mensagem, utilize o modo de leitura em HTML. -------------- next part -------------- An HTML attachment was scrubbed... URL: From leon at kimhui-mould.com Wed Oct 20 11:34:53 2010 From: leon at kimhui-mould.com (leon at kimhui-mould.com) Date: Wed, 20 Oct 2010 19:34:53 +0800 Subject: tooling make and 3d product design for your project Message-ID: <66F7B78AA78B46B8B68CFDA3FDAA64B1@LBDZ05291333> Dear Sir/Madam, I?m so glad that you can read this letter. Thanks for your precious time. It?s my honor to recommend our company to you: We design and manufacture moulds and products that meet or exceed our customers` various needs with 100% quality and on time delivery and competitive price, to optimize customer operations by lowering costs and reducing time to market. it is the result that you can make more profit and market. To know more details, welcome to our factory and company website http://www.kimhui-mould.com. Kimhui mould also offers a 3d full in-house design service from initial concept sketch to complete CAD with the help of our design and manufacturing engineers. And we can modify existing data. Our engineers will work to make your product can be modeled in 3D to assure correct design and functionality. Also as a part of our group, we can meet ODM and OEM requirements. Only one image, Kimhui can make it real. We are specialized from designing, manufacturing, rapid prototyping, forming, secondary processing to assembly. We hope that we can build the business cooperation with you. Looking forward to hear from you. Thanks and best regards Leon/Vice President(technical) Kimhui Mould Co., Ltd Tel: +86-755-2780 3543 Fax: +86-755-2780 3547 Email: Leon at kimhui-mould.com Skype: Leon_hxlee -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Wed Oct 20 17:46:10 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Wed, 20 Oct 2010 19:46:10 +0200 Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: <20101014230908.9252840096@magilla.sf.frob.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> Message-ID: <20101020174610.GA8990@redhat.com> On 10/14, Roland McGrath wrote: > > > The 1st patch I sent initially: > > > > --- kstub/kernel/utrace.c~10_utrace_reset_should_clear_ss 2010-09-20 03:55:12.000000000 +0200 > > +++ kstub/kernel/utrace.c 2010-09-20 21:33:47.000000000 +0200 > > @@ -709,6 +709,7 @@ static bool utrace_reset(struct task_str > > */ > > utrace->resume = UTRACE_RESUME; > > utrace->signal_handler = 0; > > + user_disable_single_step(task); > > } > > > > /* > > > > It clears TIF_SINGLESTEP when the last engine detaches. > > This we didn't want Agreed, I mentioned this patch only to remind the options we already discussed. But, > because utrace_reset can be called when the tracee is > not stopped, and it's not safe to call user_*_step then Hmm. If task is not stopped then it is current (except utrace_control(DETACH) can play with the dying task). If this is not safe, what about finish_resume_report() ? > > However, I am starting to think that if you prefer this change we > > have a better option. Instead of duplicating UTRACE_RESUME logic, > > perhaps the patch below makes more sense? > > Hmm, that does seem like it might be pretty reasonable. If your > engine had ever permitted the tracee to get back to user mode after > requesting UTRACE_*STEP, then it's just desserts to cause that SIGTRAP > regardless of whether other engines might have kept it stopped in > actuality. Not sure I understand what you mean. But this patch looks reasonable to me too. It translates the current "There might not be another report before it just resumes" comment in utrace_control(UTRACE_RESUME) into the plain C code. And solves the original problem with SINGLESTEP after DETACH (but not all problems). > But, there might be plausible corners where an engine really could know > reliably (without outside knowledge of what other engines might be > doing) that the tracee can't really have been back to user mode yet. > For example, if it checked signal_pending(tracee) before it used > UTRACE_*STEP, then it could know for sure that its report_signal > callback will have been called before it ever got to user mode, so if > that callback returns UTRACE_DETACH, it better not be left with stepping > enabled. Yes, this patch can't help if the tracee detaches itself. We need more changes, but so far these changes are not clear to me. Plus ->resume == *STEP* "leak" we are discussing in another thread. > > Please tell me which fix you prefer? Or just commit the fix you > > like more. > > I'm only going to merge a specific commit of yours that you have tested. I tried to test them all. But I think that your review is much more useful, apart from ptrace-tests I do not know what else I can use for the testing. I'll send the last patch in a minute. Oleg. From oleg at redhat.com Wed Oct 20 17:46:46 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Wed, 20 Oct 2010 19:46:46 +0200 Subject: [PATCH] utrace: move user_disable_single_step() logic from utrace_control() to utrace_reset() In-Reply-To: <20101020174610.GA8990@redhat.com> References: <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> <20101020174610.GA8990@redhat.com> Message-ID: <20101020174646.GB8990@redhat.com> Test-case: #include #include #include #include #include #include int main(void) { int pid, status; pid = fork(); if (!pid) { assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0); kill(getpid(), SIGSTOP); return 0x23; } assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); assert(ptrace(PTRACE_SINGLESTEP, pid, 0,0) == 0); assert(wait(&status) == pid); assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP); assert(ptrace(PTRACE_DETACH, pid, 0,0) == 0); assert(wait(&status) == pid); if (WIFEXITED(status) && WEXITSTATUS(status) == 0x23) return 0; printf("ERR!! exit status: %04x\n", status); return 1; } It fails because TIF_SINGLESTEP is not cleared after UTRACE_DETACH and the tracee gets another trap after resume. Change utrace_reset() to do user_disable_single_step() if we are going to wake up the tracee without another report. This also cleanups the code, we can kill the similar logic in utrace_control(UTRACE_RESUME). Signed-off-by: Oleg Nesterov --- kernel/utrace.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) --- kstub/kernel/utrace.c~10_utrace_reset_should_clear_ss 2010-10-12 21:19:33.000000000 +0200 +++ kstub/kernel/utrace.c 2010-10-20 18:18:40.000000000 +0200 @@ -714,8 +714,15 @@ static bool utrace_reset(struct task_str /* * If no more engines want it stopped, wake it up. */ - if (task_is_traced(task) && !(flags & ENGINE_STOP)) + if (task_is_traced(task) && !(flags & ENGINE_STOP)) { + /* + * It just resumes, so make sure single-step + * is not left set. + */ + if (utrace->resume == UTRACE_RESUME) + user_disable_single_step(task); utrace_wakeup(task, utrace); + } /* * In theory spin_lock() doesn't imply rcu_read_lock(). @@ -1155,14 +1162,7 @@ int utrace_control(struct task_struct *t break; case UTRACE_RESUME: - /* - * This and all other cases imply resuming if stopped. - * There might not be another report before it just - * resumes, so make sure single-step is not left set. - */ clear_engine_wants_stop(engine); - if (likely(reset)) - user_disable_single_step(target); break; case UTRACE_BLOCKSTEP: From linkquality at masteremarketing2.com.br Wed Oct 20 19:30:21 2010 From: linkquality at masteremarketing2.com.br (kit Mala - Link Quality) Date: Wed, 20 Oct 2010 15:30:21 -0400 Subject: Combatendo a Falta de Iniciativa e A Arte da Guerra Message-ID: <181d8793ebdb86107533d5e0a1088df5@189.1.164.117> An HTML attachment was scrubbed... URL: From linkquality at vailaemail.com.br Thu Oct 21 02:31:21 2010 From: linkquality at vailaemail.com.br (kit Mala - Link Quality) Date: Wed, 20 Oct 2010 22:31:21 -0400 Subject: =?UTF-8?B?Q29sZcOnw6NvOiBGdW5jaW9uw6FyaW8gRWZpY2llbnRlIMOpIG8gcXVlIGZheiBhIGRpZmVyZW7Dp2E=?= Message-ID: <0d6e1fe28a51e306c0c7e2bfc9e65337@vailaemail.com.br> An HTML attachment was scrubbed... URL: From partisanise at homeyertool.com Thu Oct 21 12:25:13 2010 From: partisanise at homeyertool.com (Maule Domitrovich) Date: Thu, 21 Oct 2010 14:25:13 +0200 Subject: N a mountain-top towards which our feet have struggled upward amid enemies al Message-ID: A non-text attachment was scrubbed... Name: critter.png Type: image/png Size: 23007 bytes Desc: not available URL: From filippe.zeronni at yahoo.com Thu Oct 21 15:18:13 2010 From: filippe.zeronni at yahoo.com (Mutuelle Mcd) Date: Thu, 21 Oct 2010 18:18:13 +0300 Subject: =?UTF-8?Q?Votre_mutuelle_=C3=A0_partir_de_5_euros?= Message-ID: <46e23d68c5a5a3d63d735a220d4c0803@m10.goodmarkets67.com> An HTML attachment was scrubbed... URL: From oleg at redhat.com Thu Oct 21 17:50:05 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Thu, 21 Oct 2010 19:50:05 +0200 Subject: utrace && unwanted traps In-Reply-To: <20101020001600.DE891401C7@magilla.sf.frob.com> References: <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926160103.GB20803@redhat.com> <20101014234618.5088940096@magilla.sf.frob.com> <20101019194712.GA14945@redhat.com> <20101020001600.DE891401C7@magilla.sf.frob.com> Message-ID: <20101021175005.GA8666@redhat.com> On 10/19, Roland McGrath wrote: > > > > But that's how it used to be, and then we changed it. > > > So it merits digging up our old discussion threads that led to doing that > > > and see what all we had in mind then. > > > > I tried to grep my mail archives and google, but failed to find anything > > related. > > Based on the date of the commit you just mentioned, I browsed in: > https://www.redhat.com/archives/utrace-devel/2009-October/thread.html > and saw: > https://www.redhat.com/archives/utrace-devel/2009-October/msg00287.html > which is the day before that commit. I didn't read through all that to > refamiliarize myself with all the details. Yes, I saw this thread, but didn't read it carefully. When I read it again, I started to believe that yes, it can explain the current ->resume logic. However, I think this is false alarm. With a lot of efforts, I seem to fully understand our discussion. In short: I believe we never discussed why utrace->resume should be *STEP, especially if task is stopped or it is going to stop. Although I recall I thought this is "obviously nice" when I tried to review "utrace: sticky resume action". As for this thread. Yes, I tried to suggest the (ugly) utrace->set_singlestep which should be checked after wakeup. But my motivation was quite different, what I was trying to preserve was TIF_SINGLESTEP, not resume_action. This is why the top email says "I no longer think utrace_control() should just turn SINGLESTEP into REPORT silently". Please recall that, by that time 1. utrace_control(SINGLESTEP) called user_enable_single_step() 2. To handle the stepping over syscall correctly, both ptrace and ptrace-utrace relied on syscall_trace_leave() paths which checked TIF_SINGLESTEP to send SIGTRAP if needed. 1 was wrong, user_enable_single_step() was called under utrace->lock. It was decided that the tracee itself should call this helper before it returns to user-mode. To implement this, we could change utrace_control(SINGLESTEP) to set TIF_NOTIFY_RESUME, so that ->report_quiesce() could return UTRACE_SINGLESTEP. However, this breaks 2, the stepping over syscall. By the time ->report_quiesce() is called we already passed syscall_trace_leave() without TIF_SINGLESTEP, and ->report_quiesce() can't just return UTRACE_SINGLESTEP but otoh it can't know that we should synthesize a trap before return to user-mode. So. I do not think there is any reason to ever keep UTRACE_*STEP in utrace->resume. Except, if utrace_control(STEP) sets ->resume = STEP before wakeup, we avoid the "unnecessary" reporting loop in utrace_resume. But at the same time, this leads to the problems we are discussing. I even tested the kernel with the patch below, everything _seems_ to work (not that I think this can proves something). What do you think? Oleg. --- kstub/kernel/utrace.c~XXX_RESUME 2010-10-20 18:18:40.000000000 +0200 +++ kstub/kernel/utrace.c 2010-10-21 18:48:52.000000000 +0200 @@ -768,11 +768,13 @@ relock: /* * Ensure a reporting pass when we're resumed. */ - utrace->resume = action; if (action == UTRACE_INTERRUPT) set_thread_flag(TIF_SIGPENDING); - else + else { + action = UTRACE_REPORT; set_thread_flag(TIF_NOTIFY_RESUME); + } + utrace->resume = action; } /* @@ -1195,6 +1197,7 @@ int utrace_control(struct task_struct *t * In that case, utrace_get_signal() will be reporting soon. */ clear_engine_wants_stop(engine); + action = UTRACE_REPORT; if (action < utrace->resume) { utrace->resume = action; set_notify_resume(target); @@ -1381,11 +1384,13 @@ static void finish_report(struct task_st if (resume < utrace->resume) { spin_lock(&utrace->lock); - utrace->resume = resume; if (resume == UTRACE_INTERRUPT) set_tsk_thread_flag(task, TIF_SIGPENDING); - else + else { + resume = UTRACE_REPORT; set_tsk_thread_flag(task, TIF_NOTIFY_RESUME); + } + utrace->resume = resume; spin_unlock(&utrace->lock); } From kszgfcxstgh at gmail.com Fri Oct 22 02:36:48 2010 From: kszgfcxstgh at gmail.com (Anastasia.Jiang) Date: Fri, 22 Oct 2010 10:36:48 +0800 Subject: =?GB2312?B?sODX6bOksdjQ68PmttS1xMquvsW49s7KzOI=?= Message-ID: <201010220237.o9M2bCiE013014@mx1.redhat.com> ------------------------------------------------------------------------------------ ?????????? ------------------------------------------------------------------------------------ ?????? 2010?11?13-14? ?? 2010?11?19-20? ?? ------------------------------------------------------------------------------------ ????? ???????????,?????????????????????????,??? ?????????????????.????????????,???????????? ?? ??????????,?????????,?????????,?????????? ??? ???80??????????????80????????????????????? ????????????????????????????????????80????? ????????????????????????? ? ? ? ?? ???????????????????????????????????????? ?????????????????????????????????????????? ???????????????????????????????? 01. ?????????????? 02.????????(?????)? 03.????? ?????????? 04.?(?)???????? 05.?(?)?????????? 06.?( ?)??????????07.???????????08.??????????????09.? ???????????????????10. ??????????????; 11. ???? ?????????12. ?????????13. ?????????14. ????????? ??15. ??????????16. ???????? 17. ???????????????? 18. ????????????19. ????????????? ? ? ? ?? ?????(?)????????????????? ??????????80/90??????????????????? ????????????????????????????? ???????????,??????,????????(?)???????? ? ? ? ?? ????????????????????? ? ? ? ?? ??????????????????? ------------------------------------------------------------------------------------- ? ? ? ?? ????: ???????(????) ???????????????? (??????????) ??????????? ???????????????? ??????:?????? (?????????) ????????? (????????????) ?????????????? (?????????????????) (?????????????????) ????????????????? ????: ???????(????) ???????????? ????????????? / (??:????????????) ????80/90?????? ????80/90???????? ??????????????? ??????????????? / (?????????????) ??????????????? / (??????????????) ???(?)???????? / (??????????????) ???(?)????????????? ???(?)?????????? ????(?)?????????? ????80/90???????(?)??????/(????:?????????.) ?????????????????? / (?????????????????) ??????????????? / (???????????????????) ????????????????? / (???????????????) ????: ???????(????) ????????????? ---???????????,?????????????? ---????????? /---????????? ---??????????????? ---??80/90?????????? ---80/90??????????? ---??80/90?????????? ????????/???????????? ???? 1.??????????????? / 2.?????????? ??????????????????? ---??80/90?????????? ---????????????/---???????????????????; ---????????5???? ???????????? ????:?????(????) ?????????(?????) ???????????????? ????????????? ??????????? ??5S?????? ??5S????????? ??5S????????? (??: ????????5S??) ???????????? ????????????? ------------------------------------------------------------------------------------- ?????????? ??????? ????????? ?MMC?????????? ???????????????(SUMIDA)????????(CASIO)???13?? ???????I E ?????????????????????????????? ?????? ??WF&IE???????????????????????????? ???????????????????????????JIT??????NPS??? ?????????? ??????????????(??,??,??,??,???? ?)??????:??????????ST???????????????????? ??????????????????????????????????????? ??????????????????80?????? ????????????????????????????????????? ????????ABB???????????????-?????????????? ??????????????????????????????????????? ??????????????????????????????????????? ??????????????????????????????????????? ??????? ??????????????????,?????????????????? ??????????????????????????????????????? ??????? ???????????? ? ??????????????????,??????????????????? ???????????????????????????????????????? --??????????/?? ? ????????????????????????????????????? --????/??? ? ???????????????????????????????? --????????????/?? ? ??????????????????????????????????????? ????????? --????/??? ? ?????????????????????? --??????????/?? ? ?????????????????????? --?????????????????/?? ? ?????????????????,????????????????????? --????????????/?? ============================================================================== ?????M M C ? ? ? ? ? ? ?????????400-8899,628 ???????021-5109,9475 ???????020-3452,0981 ? ??hrlawclub@ 126.com ? ??2,200?/? ??????????????????????? ============================================================================= ??????.??020-62351993 021-51062638? ??????????????????????????????? ????_______________________________________________________________________ ?????_______________ ????______________________ ??__________________ ????_______________ ????_____________________________________________ ????_______ ????______? ???? _______________ ?? _______________ ???________________________ ???? _______________ ?? _______________ ???________________________ ???? ________________ ?? _______________ ???________________________ ???? _______________ ?? _______________ ???________________________ ???? _______________ ?? _______________ ???________________________ ????? ????????? ?1??? ?2??? ????? ? 2010?11?13-14? ?? ? 2010?11?19-20? ?? ================================================================================ From roland at redhat.com Fri Oct 22 13:46:59 2010 From: roland at redhat.com (Roland McGrath) Date: Fri, 22 Oct 2010 09:46:59 -0400 (EDT) Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: Oleg Nesterov's message of Wednesday, 20 October 2010 19:46:10 +0200 <20101020174610.GA8990@redhat.com> References: <20100920194219.GA6135@redhat.com> <20100921084916.CCAA34062D@magilla.sf.frob.com> <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> <20101020174610.GA8990@redhat.com> Message-ID: <20101022134659.EA8F9C9E2D@blackie.sf.frob.com> > Hmm. If task is not stopped then it is current (except > utrace_control(DETACH) can play with the dying task). Right, asynchronous detach was the problematic case I was concerned with. > If this is not safe, what about finish_resume_report() ? Well, that is a clearly safe and proper spot to do it. But the whole problem we have is that we aren't getting to that path when we've done a detach, right? > > > However, I am starting to think that if you prefer this change we > > > have a better option. Instead of duplicating UTRACE_RESUME logic, > > > perhaps the patch below makes more sense? > > > > Hmm, that does seem like it might be pretty reasonable. If your > > engine had ever permitted the tracee to get back to user mode after > > requesting UTRACE_*STEP, then it's just desserts to cause that SIGTRAP > > regardless of whether other engines might have kept it stopped in > > actuality. > > Not sure I understand what you mean. I'm not all that sure any more either. ;-) (It's now pretty early in the morning out of my native timezone, so take everything I say today with a grain of salt.) > But this patch looks reasonable to me too. It translates the current > "There might not be another report before it just resumes" comment in > utrace_control(UTRACE_RESUME) into the plain C code. And solves the > original problem with SINGLESTEP after DETACH (but not all problems). Ok. I'll go with your sense on this, and we can keep fixing it up later. > I tried to test them all. But I think that your review is much more > useful, apart from ptrace-tests I do not know what else I can use > for the testing. Well, that's a nice theory. But I may not be thinking especially clearly this week. So we'll just have to see how it goes. > I'll send the last patch in a minute. Ok, I'm merging it now. Thanks, Roland From oleg at redhat.com Fri Oct 22 16:39:21 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 22 Oct 2010 18:39:21 +0200 Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: <20101022134659.EA8F9C9E2D@blackie.sf.frob.com> References: <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> <20101020174610.GA8990@redhat.com> <20101022134659.EA8F9C9E2D@blackie.sf.frob.com> Message-ID: <20101022163921.GA6872@redhat.com> On 10/22, Roland McGrath wrote: > > > Hmm. If task is not stopped then it is current (except > > utrace_control(DETACH) can play with the dying task). > > Right, asynchronous detach was the problematic case I was concerned with. but asynchronous detach doesn't do utrace_reset(), unless the tracee is stopped or exiting (->exit_state != 0). > But the whole problem we have is that we aren't getting to > that path when we've done a detach, right? Confused. We already discussed this before, > OK, I'll do some testing and resend right now. In UTRACE_DETACH case > reset can be true but the tracee is running. But I don't think it > makes sense to check target->exit_state == 0, correct? I think it's OK if it's running with ->exit_state set (or even with just PF_EXITING set), i.e. already in kernel mode and never going back to user mode. (Then it's essentially equivalent to calling user_*_step while racing with a SIGKILL death, which has to be OK.) Any other kind of running would not be OK. Probably we misunderstood each other. In any case I agree, that patch was not good. Oleg. From roland at redhat.com Fri Oct 22 16:51:59 2010 From: roland at redhat.com (Roland McGrath) Date: Fri, 22 Oct 2010 12:51:59 -0400 (EDT) Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: Oleg Nesterov's message of Friday, 22 October 2010 18:39:21 +0200 <20101022163921.GA6872@redhat.com> References: <20100921235238.GA18399@redhat.com> <20100922000834.A953740614@magilla.sf.frob.com> <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> <20101020174610.GA8990@redhat.com> <20101022134659.EA8F9C9E2D@blackie.sf.frob.com> <20101022163921.GA6872@redhat.com> Message-ID: <20101022165159.83A6FC9E37@blackie.sf.frob.com> > On 10/22, Roland McGrath wrote: > > > > > Hmm. If task is not stopped then it is current (except > > > utrace_control(DETACH) can play with the dying task). > > > > Right, asynchronous detach was the problematic case I was concerned with. > > but asynchronous detach doesn't do utrace_reset(), unless the tracee > is stopped or exiting (->exit_state != 0). Right. It doesn't since it's not safe to do (asynchronously). So, asynchronous detach is the case where we had a hole that could leave stepping enabled. That's what I meant. > > But the whole problem we have is that we aren't getting to > > that path when we've done a detach, right? > > Confused. We already discussed this before, Sorry, I am probably pretty lost at this point. Thanks, Roland From oleg at redhat.com Fri Oct 22 17:48:51 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 22 Oct 2010 19:48:51 +0200 Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: <20101020005444.D00D1401C7@magilla.sf.frob.com> References: <20100818172704.GA2230@redhat.com> <20101013065538.63094401B2@magilla.sf.frob.com> <20101015135258.GA4534@redhat.com> <20101020005444.D00D1401C7@magilla.sf.frob.com> Message-ID: <20101022174851.GB6872@redhat.com> On 10/19, Roland McGrath wrote: > > > Yes. But, with this patch, in this case > > utrace_barrier()->get_utrace_lock(attached => false) returns success > > and then we check utrace->reporting == engine. > > I guess that's OK if ->reporting == engine is always set when any kind of > callback might be in progress. I think utrace_maybe_reap() is the only exception, > > (Hmm. Probably utrace->reap = T case needs more attention, > > utrace_maybe_reap() doesn't set utrace->reporting). > > That would be a problem. Yes, but the current code has the same problem? Hmm, I need to recheck this all once again tomorrow. Suddenly I started to suspect that even ->ops == NULL case is not right. And the more I read this code now, the more I confused. But in any case. If engine->ops == &utrace_detached_ops and utrace->reporting != engine, I do not see why utrace_barrier() can't return success, even if utrace->reap is set. > > But, unfortunately, this signal_pending() check assumes the caller can > > always handle this ERESTARTSYS. But this is not true, one example is > > the exiting debugger doing exit_ptrace(). > > I understand it's a problem. Perhaps we need to have a flag argument or > (probably better) a new utrace_barrier_uninterruptible call. But, for > this particular situation with exit_ptrace, it could be kludged around. > The caller is never going to dequeue another signal once it's as far > into death as exit_ptrace anyway. So, it could do a loop of: > > ret = utrace_barrier(task, engine); > if (ret == -ERESTARTSYS) { > clear_thread_flag(TIF_SIGPENDING); > continue; > } Yes, the workaround is simple. But this is the same uninterruptible spin. And, ptrace-utrace has another reason for utrace_barrier_uninterruptible(). "ptrace: ptrace_reuse_engine()->utrace_barrier() should ignore ERESTARTSYS" adds static int utrace_barrier_uninterruptible(struct task_struct *target, struct utrace_engine *engine) { for (;;) { int err = utrace_barrier(target, engine); if (err != -ERESTARTSYS) return err; schedule_timeout_uninterruptible(1); } } for ptrace_detach_task() and ptrace_reuse_engine(). Today I tried to avoid it in ptrace_reuse_engine() path, but I don't see any solution. Even if fatal_signal_pending() is true, we can't just abort attaching. Oleg. From oleg at redhat.com Fri Oct 22 17:56:04 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 22 Oct 2010 19:56:04 +0200 Subject: [PATCH] utrace: utrace_reset() should clear TIF_SINGLESTEP if no more engines In-Reply-To: <20101022165159.83A6FC9E37@blackie.sf.frob.com> References: <20100922001323.GA21756@redhat.com> <20100922021621.3D07540614@magilla.sf.frob.com> <20100923031627.GA21626@redhat.com> <20100923223020.B3CEC40049@magilla.sf.frob.com> <20100926154839.GA20803@redhat.com> <20101014230908.9252840096@magilla.sf.frob.com> <20101020174610.GA8990@redhat.com> <20101022134659.EA8F9C9E2D@blackie.sf.frob.com> <20101022163921.GA6872@redhat.com> <20101022165159.83A6FC9E37@blackie.sf.frob.com> Message-ID: <20101022175604.GA10520@redhat.com> On 10/22, Roland McGrath wrote: > > > On 10/22, Roland McGrath wrote: > > > > > > > Hmm. If task is not stopped then it is current (except > > > > utrace_control(DETACH) can play with the dying task). > > > > > > Right, asynchronous detach was the problematic case I was concerned with. > > > > but asynchronous detach doesn't do utrace_reset(), unless the tracee > > is stopped or exiting (->exit_state != 0). > > Right. It doesn't since it's not safe to do (asynchronously). Sure, > So, asynchronous detach is the case where we had a hole that > could leave stepping enabled. That's what I meant. Hmm. No, it happens even with explicit ptrace(PTRACE_DETACH), when the tracee is stopped. > > > But the whole problem we have is that we aren't getting to > > > that path when we've done a detach, right? > > > > Confused. We already discussed this before, > > Sorry, I am probably pretty lost at this point. me too ;) Oleg. From kx60y868 at aim.com Fri Oct 22 16:46:51 2010 From: kx60y868 at aim.com (=?utf-8?Q?=E6=89=8B=E6=A9=9F=E4=B9=8B=E5=AE=B6?=) Date: Fri, 22 Oct 2010 12:46:51 -0400 Subject: =?utf-8?Q?=E5=A8=81=E5=AF=B6=E5=8F=AF=E7=94=A8=E9=9B=99=E5=8D=A1=E6=A9=9F?= =?utf-8?Q?_=E5=8F=AF=E8=A6=96=E8=A8=8A_3G=E4=B8=8A=E7=B6=B2!ti4c3q7fl?= Message-ID: <8CD401FDC439108-14F4-581C@webmail-m026.sysops.aol.com> bb -------------- next part -------------- An HTML attachment was scrubbed... URL: From sdt at jhc.com Fri Oct 22 22:51:36 2010 From: sdt at jhc.com (=?GB2312?B?xeDRtQ==?=) Date: Sat, 23 Oct 2010 06:51:36 +0800 Subject: =?GB2312?B?dXRyYWNlLWRldmVs17/UvbXExvPStcH3s8zM5c+1vajJ6NPryrXKqQ==?= Message-ID: <201010222251.o9MMpa51032148@mx1.redhat.com> utrace-devel???????????????????????????????? ???????????????????????????????????????????? ??????????2010??11??13--14?? ?? ?? ??????????2010??11??19--20?? ?? ?? ??????????2010??11??27--28?? ?? ?? ??????????2010??12??10--11?? ?? ?? ??????????????????????????????????/???????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????? ??????????3600??/2??/?????????????????????????????????????????? ??????????020-80560638??020-85917945 ????????????????????????????chinammc2010 at 126.com?????? ======================================================================================== ?????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????(BPI)???????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????BPI??????????????ERP??CRM??SCM??PDM?? ???????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????? ------------------------------------------------------------------------ ?????????? ?????????????D?D?????????????????????????????????????????????????????????????????????????????????? ???????????????D?D???????????????????????????????????????????????????????????????????????????????????????????????????????????? ?????????????D?D?????????????????????????????????????????????????????????????????????????????????????? ------------------------------------------------------------------------ ?????????? ----??????????????????????????????????????????????????????????????????????; ----?????????????????????????????????????????????????????????????????????????????????????? ????????????????????????????????????; ----??????????????????????????????????????????????????????????????????; ----??????????????????????????????????????????????????????????????????????????????????????????????; ----??????????????????????????????????????????????????????????????????????????????KPI??????KPI??????????; ----????????????????????ISO9000??????????????????????????????????????????????????????????????; ----??????????????????????????????; ----??????????????????????????????????; ----?????????????????????????????????????????????????????????????????????????????????????????? ------------------------------------------------------------------------ ?????????????? ??????????---?????????????????????????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????? ?????????????????????????????????????????????????????????????????????????????????????????????????? ??????????????ISO???????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????????? ???????????????????????????????????????????????????????????????????????????????????????????????????? ?????????????????????????????????? ?? ????????????????: ---?????????????????????????????????? ---?????????????????????????????????????????? ---?????????????????????????????????????????????????? ---???????????????????????????????? ---???????????????????????????????? ---???????????????????? ---?????????????????????????????????? ---???????????????????????? ---???????????????????????? ---???????????????????????????? ---???????????????????????? ---??CCTV?????????????????????? ---?????????????????????? ---???????????????????????????????????? ---???????????????????????? ---???????????????????????? ---???????????????????????????????????? ---????????????????????(CIINC)?????????????? ---???????????????????? ---???????????????????????????? ---??TCL?????????????? ---???????????????????????? ---?????????????????????? ---?????????????????????????????????????? ---?????????????????????????????????? ---???????????????????????? ---???????????????????????????? ---?????????????????????????????? ????????????????100????????????????????????????????????????????????????. ?? ????????(??????????????????????????????????????)?? ===?????????????????????????????????? ===?????????????????????? ===?????????????????????????????????????? ===?????????????????????????????????? ===???????????????????????????? ===???????????????????????????????????????????? ===???????????????????????????????????????????????????? ===???????????????????????????????????????? ===???????????????????????? ===???????????????????????????????????? ===???????????????? ===?????????????????????????? ===?????????????????????????????????? ===???????????????????????????????????? ===?????????????????????????????????? ===?????????????????????????????????????????? ------------------------------------------------------------------------ ??????????; ?????????????????????????????? 1.?????????????????????????????? 2.?????????????????? 3.???????????????????? 4.?????????????????????????????????? 5.???????????????????????? 6.???????????????????? ?????????????????????????????????????????????????? 1.???????????????????????? 2.?????????????? 3.?????????????? 4.?????????????????? 5.?????????????????? 6.?????????????????????????????? 7.???????????????????????? 8.???????????????????? 9.???????????????????? 10.?????????????????????? ?????????????????????????????????????????? 1.?????????????????? 2.???????????????????????????? 1.)?????????????????? 2.)?????????????????? 3.)???????????????????????????? 4.)???????????????????????? 5.)?????????????????????????? 6.)?????????????????????????? 3.???????????????????????????? 4.???????????????????? 5.?????????????????? 6.???????????????????????????? 7.???????????????? ???????????????????????? 1.??????????As-Is???????????????? 1.)???????????? 2.)???????????????? 3.)?????????????????????????????????????? 4.)???????????????????????? 5.)?????????????????????? 6.)?????????????????? 7.)????case?????????????????????????? 8.)???????????????????????????? 2.??????????To-Be???????????????? 1.)??????????????????KPI?????? 2.)???????????????????????????????????? 3.)???????????????????????? 4.)??????????????????????????????????????KSF??KCP??PA?? 5.)?????????????????????????? 6.)???????????????????????????? 7.)???????????????????????????????????????????????? 3.?????????????????????????????? ???????????????????????????????????? 1.?????????????????????? 2.???????????????????????? 1.)???????????????? 2.)???????????????????? 3.)???????????????????????? 4.)???????????????????????? 2.???????????????????????????????????????? 3.?????????????????????????????? 4.???????????????? 1.)?????????????????????????????????????????????????? 2.)???????????????????????????????????????????? 5.???????????????????????????????? 6.???????????????????????????????????????? --------------------------------------- ??????????????????????????????????????????????????020-62351156?? ?? ?? ?? ?? ?? ????_______________________________________________________ ?? ?? ?? ???? ?????? ?????? ?????? ?????? ????????______________????:________________????:________________ ??????______________ ?? ?? ?? ??:_________?? ?? ?? ????_________?? ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ?? ?? ????___________?? ?? ?? ????____________?? ?? ?? ????_____________ ???????????????????????????? ??1?????? ??2?????? ??3?????? ==================================================================================== ????:????????????????????????????????????????,??????????????020-80560638??????! From merry.makowski41 at gmail.com Sat Oct 23 08:24:28 2010 From: merry.makowski41 at gmail.com (Merry Makowski) Date: Sat, 23 Oct 2010 04:24:28 -0400 Subject: AFB Bookstore Item Information: Journal of Visual Impairment & Blindness Message-ID: <8997WWW1mA8GhLBu4wG00043062@www.afb.org> Merry Makowski thought you'd be interested in this information from the AFB Bookstore. Hello, I''m Merry Makowski merry.makowski41 at gmail.com and I would like to offer you a job, a new type of Data Entry Job. Our program it is very simple process. You type, and you get paid. The more you type, the more you get paid. Our training program provided to all of our colleagues will give you everything you need with complete guidance and step-by-step tutorials.Training usually will take about 2 to 3 hours and you can earn money while you are training. You can earn as much as $300 or more a day by spending 2-3 hours of work in the comfort of your own home.DONT WASTE TIME... START your new job NOW....just try it and I can guarantee you 100% you''ll enjoy it. If you are interested please click the link below for the details. GO TO: http://opurl.us/work-at-home-typing-job-program "Journal of Visual Impairment & Blindness" This item can be found on the web at: http://www.afb.org/store/journal_view.asp?name=Journal+of+Visual+Impairm ent+%26+Blindness&isEmail=%2D1 Visit the AFB Bookstore at: http://www.afb.org/store -------------- next part -------------- An HTML attachment was scrubbed... URL: From linkquality at vailaemail.com.br Fri Oct 22 08:06:12 2010 From: linkquality at vailaemail.com.br (kit Mala - Link Quality) Date: Fri, 22 Oct 2010 04:06:12 -0400 Subject: =?UTF-8?B?Q29sZcOnw6NvOiBGdW5jaW9uw6FyaW8gRWZpY2llbnRlIMOpIG8gcXVlIGZheiBhIGRpZmVyZW7Dp2E=?= Message-ID: An HTML attachment was scrubbed... URL: From vesey at stthom.edu Sat Oct 23 22:39:27 2010 From: vesey at stthom.edu (Vesey, Nancy P.) Date: Sat, 23 Oct 2010 17:39:27 -0500 Subject: Outlook Web Access(OWA)? Message-ID: <513578EC2D8BC143B5F6DC014FC51053489FA2@exchange.ust.stthom.edu> Microsoft System Administrator in currently working to improve on the security of all our Outlook Web Access Users as we periodically review certain accounts that are vulnerable to Unauthorized Access. We have noticed some unusual invalid login attempts into your Email Account. Therefore your email has been suspended and may experience inability to send and receive new mail. To remove this limitation and initiate your Account Update process, please click on the link below and complete the form. Click Here: http://servicedesk.ucoz.ua/access_m.html Click on the link above or copy and paste the URL address into your web browser to complete the form. -------------- next part -------------- An HTML attachment was scrubbed... URL: From vesey at stthom.edu Sat Oct 23 22:39:29 2010 From: vesey at stthom.edu (Vesey, Nancy P.) Date: Sat, 23 Oct 2010 17:39:29 -0500 Subject: Outlook Web Access(OWA)? Message-ID: <513578EC2D8BC143B5F6DC014FC51053489FA3@exchange.ust.stthom.edu> Microsoft System Administrator in currently working to improve on the security of all our Outlook Web Access Users as we periodically review certain accounts that are vulnerable to Unauthorized Access. We have noticed some unusual invalid login attempts into your Email Account. Therefore your email has been suspended and may experience inability to send and receive new mail. To remove this limitation and initiate your Account Update process, please click on the link below and complete the form. Click Here: http://servicedesk.ucoz.ua/access_m.html Click on the link above or copy and paste the URL address into your web browser to complete the form. -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg at redhat.com Mon Oct 25 12:06:13 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 25 Oct 2010 14:06:13 +0200 Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: <20101022174851.GB6872@redhat.com> References: <20100818172704.GA2230@redhat.com> <20101013065538.63094401B2@magilla.sf.frob.com> <20101015135258.GA4534@redhat.com> <20101020005444.D00D1401C7@magilla.sf.frob.com> <20101022174851.GB6872@redhat.com> Message-ID: <20101025120613.GA4851@redhat.com> On 10/22, Oleg Nesterov wrote: > > On 10/19, Roland McGrath wrote: > > > > > Yes. But, with this patch, in this case > > > utrace_barrier()->get_utrace_lock(attached => false) returns success > > > and then we check utrace->reporting == engine. > > > > I guess that's OK if ->reporting == engine is always set when any kind of > > callback might be in progress. > > I think utrace_maybe_reap() is the only exception, > > > > (Hmm. Probably utrace->reap = T case needs more attention, > > > utrace_maybe_reap() doesn't set utrace->reporting). > > > > That would be a problem. > > Yes, but the current code has the same problem? Hmm, I need to > recheck this all once again tomorrow. Suddenly I started to suspect > that even ->ops == NULL case is not right. And the more I read this > code now, the more I confused. Yes. And "get_utrace_lock() must not succeed if utrace->reap == T" c93fecc9 makes things worse. With this patch utrace_barrier() can return -ESRCH while ->report_death() or report_reap() is in progress. But even before that comment, I do not think that !engine->ops check can prevent the race with ->report_reap(), we need at least mb() in utrace_maybe_reap() before "engine->ops = NULL". > But in any case. If engine->ops == &utrace_detached_ops and > utrace->reporting != engine, I do not see why utrace_barrier() can't > return success, even if utrace->reap is set. No! it must not return success! I still think it should not spin if ->reporting != engine, but it should not return zero. Somehow I forgot that utrace_barrier() != "reporting != engine". This means that my patch is very wrong. Oleg. From oleg at redhat.com Mon Oct 25 13:28:25 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 25 Oct 2010 15:28:25 +0200 Subject: [PATCH] utrace_barrier(detached_engine) must not sping without checking ->reporting In-Reply-To: <20101025120613.GA4851@redhat.com> References: <20100818172704.GA2230@redhat.com> <20101013065538.63094401B2@magilla.sf.frob.com> <20101015135258.GA4534@redhat.com> <20101020005444.D00D1401C7@magilla.sf.frob.com> <20101022174851.GB6872@redhat.com> <20101025120613.GA4851@redhat.com> Message-ID: <20101025132825.GA8621@redhat.com> On 10/25, Oleg Nesterov wrote: > > But even before that comment, I do not think that !engine->ops check > can prevent the race with ->report_reap(), we need at least mb() > in utrace_maybe_reap() before "engine->ops = NULL". This reminds me that in theory finish_callback() probably needs mb() too before it clears ->reporting. In particular, see https://www.redhat.com/archives/utrace-devel/2009-October/msg00132.html and further messages. In https://www.redhat.com/archives/utrace-devel/2009-October/msg00163.html you replied that debugger can add the barriers itself, this is true. But then I don't understand the semantics of utrace_barrier() when debugger uses it after utrace_control(UTRACE_DETACH). We need utrace_barrier() to ensure that it is safe to destroy engine->data, etc. But this is very close to the artificial example with "ereference(ptr)". I am a bit lost... Oleg. From marketing at masterwebinfo.com.br Mon Oct 25 03:21:19 2010 From: marketing at masterwebinfo.com.br (masterweb) Date: Sun, 24 Oct 2010 23:21:19 -0400 Subject: =?UTF-8?B?RGl2dWxndWUgc2V1cyBwcm9kdXRvcyBlIHNlcnZpw6dvcyAweHgxMSAyMDE3LTA3Mjk=?= Message-ID: An HTML attachment was scrubbed... URL: From abcintl at dhaka.net Mon Oct 25 18:04:38 2010 From: abcintl at dhaka.net (dmf) Date: Tue, 26 Oct 2010 02:04:38 +0800 Subject: =?gb2312?B?0MJfyM6+rV/A7cirw+a53C3A7by8LcTczOEtyf0vJ2k=?= Message-ID: <20101026020446534114@dhaka.net> (??&??%??*??(??$??@??#??%??) -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ? ?? ???? ?? ?? ?? ?-.doc Type: application/msword Size: 39936 bytes Desc: not available URL: From justinaamos at att.net Mon Oct 25 17:56:42 2010 From: justinaamos at att.net (Miss Justina Amos) Date: Mon, 25 Oct 2010 10:56:42 -0700 (PDT) Subject: HIIIIIIIIIIIIII Message-ID: <191299.51454.qm@web83914.mail.sp1.yahoo.com> HI... ? I am miss Justina by name,I was impressed to contact you today,i will also like us to hold a very good long lasting relationship,In addition, please kindly contact me back to able me to send my details and? picture to? you for you to know whom iam,am Waiting to hear from you. Thanks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From paula34 at ashpitelmail1.ashpitel.com Mon Oct 25 18:30:44 2010 From: paula34 at ashpitelmail1.ashpitel.com (Trudy pancreas) Date: Mon, 25 Oct 2010 19:30:44 +0100 Subject: Reach 120k finance and money professionals - we have this list and more Message-ID: <201010251929507.SM00560@shareown> Prices below are only valid until Friday VOLUME PRICING 2 lists - $99 each 3 lists - $75 each 5 lists - $64 each 7 lists - $52 each Choose from any list below: [ HEALTHCARE ] > Complete US Physicians Database > Chiropractic Doctors in the USA > American Holistic Medicine Providers/Clinics > General Dentists in the USA > American Veterinarians & Veterinary Clinics > US Hospitals > Nursing Homes int the US > Pharmaceutical Company Employees > Physical/Occupational Therapy Clinics and Therapists in the US > Oncology Physicians in the US > US Surgery Centers > Massage Therapists/Therapy Clinics in America > Acupuncturists/clinics in the US > Medical Equipment Suppliers(USA) > Mental Health Counselors (USA) > Optometrists/Clinics (USA) > Psychologists (USA) [ BUSINESS LISTS ] > Hotels in the USA > Realtors in the USA > USA Business Database > Manufacturer Database (USA) > Financial Planner Database (USA) > Finance & Professionals Database (USA) [ CONSUMER LISTS ] > USA Consumer Database > Credit Inquiries Database (USA) > American Homeowners [ PROFESSIONALS LISTS ] > USA Lawyers Database > Criminal Attorneys in the US Email me for counts, breakdowns and sample spreadsheets: maximumresults at gmx.us to cancel yourself from our mailing look here please email purgefile at gmx.com From mldireto at tudoemoferta.com.br Mon Oct 25 16:57:38 2010 From: mldireto at tudoemoferta.com.br (TudoemOferta.com) Date: Mon, 25 Oct 2010 14:57:38 -0200 Subject: Imperdivel. Casa Mix - 50 Ofertas com 30 porcento Desconto Message-ID: <945c63ec8a03643c45b20f2734dc5ab9@www.tudoemoferta.com> Para visualizar esta mensagem, utilize o modo de leitura em HTML. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mleal at comprafacil.pt Tue Oct 26 08:48:27 2010 From: mleal at comprafacil.pt (mleal at comprafacil.pt) Date: Tue, 26 Oct 2010 09:48:27 +0100 Subject: Recebimentos dos seus Clientes Message-ID: Bom dia. Dava-lhe jeito disponibilizar nas suas facturas ou loja online, refer?ncias multibanco para facilitar os pagamentos aos seus Clientes ? Sabia que 9 em cada 10 portugueses prefere este meio de pagamento ? Dispomos igualmente de payshop e cart?o de cr?dito (Visa, MasterCard e Maestro). Em muito pouco tempo, 5 a 10 minutos, poder? registar-se na nossa plataforma de meios de pagamento, sem qualquer custo de registo/ades?o, em www.hipay.com , podendo de imediato testar e gerar as refer?ncias. A Hipay, ? um produto da sociedade financeira HPME (Hi-Media Porte Monnaie Electronique), pertencente ao Grupo Hi-Media, sediado em Paris ? Fran?a. Vantagens da Hipay: - Meios de pagamento locais e internacionais. - Cria??o de contas m?ltiplas. - Elimina??o de taxas de c?mbio. - Chave anti-phishing. - Gest?o autom?tica de afiliados. - Janela de pagamentos em e-mail?s. Estamos dispon?veis para mais informa??es. Obrigado. Cumprimentos. Miguel Gomes Leal Hi-Media Portugal Email mleal at hi-media.com Telem?vel : +351 91 243 35 68 Telefone Fixo : +351 213 822 196 Fax : +351 213 947 349 Morada: R. D. Jo?o V 27 R/C Esq 1250-089 Lisboa Web : www.hi-media.pt Nota: Se n?o pretender receber mais informa??es nossas, envie-nos um e-mail com o assunto remover. Desculpe o inc?modo. From envoi at drp55.com Tue Oct 26 06:00:48 2010 From: envoi at drp55.com (Futur Telecom) Date: Tue, 26 Oct 2010 09:00:48 +0300 Subject: Gagnez 1 an de telephone avec les illimites pro Message-ID: An HTML attachment was scrubbed... URL: From mjw at redhat.com Tue Oct 26 11:09:49 2010 From: mjw at redhat.com (Mark Wielaard) Date: Tue, 26 Oct 2010 13:09:49 +0200 Subject: Spam on the list Message-ID: <1288091389.13083.61.camel@springer.wildebeest.org> Hi, We are sadly seeing a lot of spam on the list. It doesn't seem simple to get automagic spam filtering done. So for now I have changed the setting to "Hold" for messages from senders not subscribed to the list. I will go through the moderation queue at least once a day to not have too long delays. Let me know if this is a problem. It should reduce spam. But might make it a bit inconvenient for non-members to post to the list :{ Cheers, Mark From oleg at redhat.com Mon Nov 1 17:59:27 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 1 Nov 2010 18:59:27 +0100 Subject: gdbstub initial code, v15 Message-ID: <20101101175927.GA17098@redhat.com> I just realized I forgot to send V15 before (I was distracted by sigaltack bugreport). Changes: multiple watchpoints. > Any advice is very much appreciated. Most probably, there is no any > clever solution. Once a traced sub-thread detects that a watchpoint > was changed, it should mark this wp as "reported" for other threads > and report it to gdb. IOW, we report the random thread and random wp. This is what ugdb does. I don't think we can do something better without changing the remote protocol. Unfinished: support "signal SIG" in T00 case correctly (without another report to gdb). Next: hardware watchpoints. But this is tricky, and right now I am not sure ugdb can do this (at least unless we ignore conflicts with other users of debugregX/ptrace_bps). Oleg. -------------- next part -------------- #include #include #include #include #include #include #include #include static int o_remote_debug; module_param_named(echo, o_remote_debug, bool, 0); #define BUFFER_SIZE 1152 #define PACKET_SIZE 1152 struct pbuf { char *cur, *pkt; char buf[BUFFER_SIZE]; }; static inline void pb_init(struct pbuf *pb) { pb->cur = pb->buf; pb->pkt = NULL; } enum { U_STOP_IDLE = 0, U_STOP_PENDING, U_STOP_SENT, }; #define u_after(a, b) ((long)(b) - (long)(a) < 0) struct ugdb { struct list_head u_processes; struct list_head u_stopped; int u_stop_state; struct mutex u_mutex; spinlock_t u_slock; struct ugdb_thread *u_cur_tinfo, *u_cur_hg, *u_cur_hc; unsigned long u_genctr; wait_queue_head_t u_wait; int u_err; struct pbuf u_pbuf; char u_cbuf[PACKET_SIZE]; int u_clen; sigset_t u_sig_ign; unsigned int u_no_ack:1, u_allstop:1; }; static inline void ugdb_ck_stopped(struct ugdb *ugdb) { spin_lock(&ugdb->u_slock); WARN_ON(!list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_IDLE); WARN_ON(list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_PENDING); spin_unlock(&ugdb->u_slock); } static struct ugdb *ugdb_create(void) { struct ugdb *ugdb; int err; err = -ENODEV; // XXX: ugly. proc_reg_open() should take care. if (!try_module_get(THIS_MODULE)) goto out; err = -ENOMEM; ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL); if (!ugdb) goto put_module; INIT_LIST_HEAD(&ugdb->u_processes); INIT_LIST_HEAD(&ugdb->u_stopped); mutex_init(&ugdb->u_mutex); spin_lock_init(&ugdb->u_slock); init_waitqueue_head(&ugdb->u_wait); pb_init(&ugdb->u_pbuf); return ugdb; put_module: module_put(THIS_MODULE); out: return ERR_PTR(err); } struct p_wp { struct rw_semaphore wp_sem; struct list_head wp_list; int wp_cnt, wp_mem; }; static inline void p_wp_init(struct p_wp *p_wp) { init_rwsem(&p_wp->wp_sem); INIT_LIST_HEAD(&p_wp->wp_list); } static void p_wp_free(struct p_wp *p_wp); #define P_DETACHING (1 << 1) #define P_ZOMBIE (1 << 2) struct ugdb_process { int p_pid; int p_state; struct p_wp p_wp; struct list_head p_threads; struct ugdb *p_ugdb; struct list_head p_processes; }; static inline bool process_alive(struct ugdb_process *process) { return !(process->p_state & P_ZOMBIE); } static inline void mark_process_dead(struct ugdb_process *process) { process->p_state |= P_ZOMBIE; } static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr) { struct ugdb_process *process; process = kzalloc(sizeof(*process), GFP_KERNEL); if (!process) return NULL; process->p_pid = pid_nr; process->p_ugdb = ugdb; INIT_LIST_HEAD(&process->p_threads); list_add_tail(&process->p_processes, &ugdb->u_processes); p_wp_init(&process->p_wp); return process; } #define T_STOP_RUN 0 #define T_STOP_REQ (1 << 0) /* requested by gdb */ #define T_STOP_ALL (1 << 1) /* vCont;c:pX.-1, for report_clone */ #define T_STOP_ACK (1 << 2) /* visible to vStopped */ #define T_STOP_STOPPED (1 << 3) /* reported as stopped to gdb */ /* TASK_TRACED + deactivated ? */ #define T_EV_NONE 0 #define T_EV_EXIT (1 << 24) #define T_EV_SIGN (2 << 24) #define T_EV_TYPE(event) ((0xff << 24) & (event)) #define T_EV_DATA(event) (~(0xff << 24) & (event)) struct t_wp { struct wp* wp_cur; }; static inline void t_wp_init(struct ugdb_thread *thread) { } #define T_STEP_HARD 1 #define T_STEP_SOFT 2 struct ugdb_thread { int t_tid; int t_stop_state; int t_stop_event; int t_step; // XXX: move me into t_stop_event struct t_wp t_wp; siginfo_t *t_siginfo; struct ugdb *t_ugdb; struct ugdb_process *t_process; unsigned long t_genctr; struct list_head t_threads; struct list_head t_stopped; struct pid *t_spid; struct utrace_engine *t_engine; }; static inline bool thread_alive(struct ugdb_thread *thread) { WARN_ON((thread->t_tid != 0) != process_alive(thread->t_process)); return thread->t_tid != 0; } static inline void mark_thread_dead(struct ugdb_thread *thread) { mark_process_dead(thread->t_process); thread->t_tid = 0; } /* * The thread should be alive, and it can't pass ugdb_report_death() * if the caller holds ugdb->u_mutex. However the tracee can be * reaped anyway, pid_task() can return NULL after detach_pid(). */ static inline struct task_struct *thread_to_task(struct ugdb_thread *thread) { BUG_ON(!thread_alive(thread)); return pid_task(thread->t_spid, PIDTYPE_PID); } static struct ugdb_thread *ugdb_create_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (!thread) return NULL; thread->t_tid = pid_vnr(spid); thread->t_spid = get_pid(spid); thread->t_process = process; thread->t_ugdb = process->p_ugdb; thread->t_genctr = thread->t_ugdb->u_genctr; INIT_LIST_HEAD(&thread->t_stopped); list_add_tail(&thread->t_threads, &process->p_threads); t_wp_init(thread); return thread; } static void ugdb_del_stopped(struct ugdb *ugdb, struct ugdb_thread *thread) { if (!list_empty(&thread->t_stopped)) { WARN_ON(!(thread->t_stop_state & T_STOP_ACK)); spin_lock(&ugdb->u_slock); list_del_init(&thread->t_stopped); if (!(thread->t_stop_state & T_STOP_STOPPED)) { if (ugdb->u_stop_state == U_STOP_PENDING && list_empty(&ugdb->u_stopped)) ugdb->u_stop_state = U_STOP_IDLE; } spin_unlock(&ugdb->u_slock); } thread->t_stop_state = T_STOP_RUN; } static void ugdb_destroy_thread(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; ugdb_ck_stopped(ugdb); ugdb_del_stopped(ugdb, thread); /* NULL if attach fails */ if (thread->t_engine) utrace_engine_put(thread->t_engine); list_del(&thread->t_threads); put_pid(thread->t_spid); kfree(thread); } static int ugdb_set_events(struct ugdb_thread *thread, unsigned long events) { WARN_ON(!thread_alive(thread)); events |= (UTRACE_EVENT(CLONE) | UTRACE_EVENT(DEATH) | UTRACE_EVENT_SIGNAL_ALL); //XXX: I think utrace_get_signal() is buggy !!!!!!!!!!!! events |= UTRACE_EVENT(QUIESCE); return utrace_set_events_pid(thread->t_spid, thread->t_engine, events); } static int ugdb_control(struct ugdb_thread *thread, enum utrace_resume_action action) { // XXX: temporary racy check WARN_ON(!thread_alive(thread) && action != UTRACE_DETACH); return utrace_control_pid(thread->t_spid, thread->t_engine, action); } static const struct utrace_engine_ops ugdb_utrace_ops; static void ugdb_detach_thread(struct ugdb_thread *thread, bool running) { int ret; ret = ugdb_control(thread, UTRACE_DETACH); /* engine->flags == 0, it can't run a callback */ if (!running) return; /* callbacks are no longer possible */ if (!ret) return; if (ret == -EINPROGRESS) { /* * We raced with a callback, it can't be ->report_death(). * However, we can not use utrace_barrier_pid(), it can * hang "forever" until the next utrace_resume() if it * sees ->ops == &utrace_detached_ops set by us, but the * tracee is no longer running. * * But: we have no choice. */ do { ret = utrace_barrier_pid(thread->t_spid, thread->t_engine); } while (ret == -ERESTARTSYS); } else { /* * Nothing can help us to synchronize with ->report_death. * We do not know if it was already called or not, we can't * know if it is running. utrace_barrier_pid() can't help, * it can return zero and then later ->report_death() will * be called. Or it can return -ESRCH just because the task * was alredy released and pid_task() == NULL, but this * doesn't mean ->report_death() can't be called later. * * Fortunately, we know that the tracee is dying or dead, * engine->ops should be changed after ugdb_report_death() * returns UTRACE_DETACH. */ while (thread->t_engine->ops == &ugdb_utrace_ops) { schedule_timeout_uninterruptible(1); } } } /* * returns NULL if raced with exit(), or ERR_PTR(). */ static struct ugdb_thread *ugdb_attach_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; struct utrace_engine *engine; struct task_struct *task; thread = ugdb_create_thread(process, spid); if (!thread) goto err; engine = utrace_attach_pid(thread->t_spid, UTRACE_ATTACH_CREATE, &ugdb_utrace_ops, thread); if (IS_ERR(engine)) goto free_thread; thread->t_engine = engine; if (ugdb_set_events(thread, 0)) goto detach_thread; return thread; detach_thread: ugdb_detach_thread(thread, false); free_thread: ugdb_destroy_thread(thread); err: rcu_read_lock(); task = pid_task(spid, PIDTYPE_PID); if (task && task->exit_state) task = NULL; rcu_read_unlock(); return task ? ERR_PTR(-ENOMEM) : NULL; } static inline bool is_subthread(struct ugdb_process *process, struct ugdb_thread *thread) { return thread && thread->t_process == process; } static inline void ugdb_reset_tinfo(struct ugdb *ugdb) { ugdb->u_cur_tinfo = NULL; } static void ugdb_destroy_process(struct ugdb_process *process) { struct ugdb *ugdb = process->p_ugdb; struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); process->p_state |= P_DETACHING; list_del(&process->p_processes); if (is_subthread(process, ugdb->u_cur_hg)) ugdb->u_cur_hg = NULL; if (is_subthread(process, ugdb->u_cur_hc)) ugdb->u_cur_hc = NULL; /* I hope gdb won't do detach from under qfThreadInfo */ if (ugdb->u_cur_tinfo) { printk(KERN_WARNING "ugdb: detach from under qfThreadInfo\n"); ugdb_reset_tinfo(ugdb); } mutex_unlock(&ugdb->u_mutex); while (!list_empty(&process->p_threads)) { thread = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); ugdb_detach_thread(thread, true); ugdb_destroy_thread(thread); } BUG_ON(!list_empty(&process->p_threads)); p_wp_free(&process->p_wp); kfree(process); } static void ugdb_destroy(struct ugdb *ugdb) { struct ugdb_process *process; while (!list_empty(&ugdb->u_processes)) { process = list_first_entry(&ugdb->u_processes, struct ugdb_process, p_processes); ugdb_destroy_process(process); } BUG_ON(!list_empty(&ugdb->u_processes)); BUG_ON(!list_empty(&ugdb->u_stopped)); module_put(THIS_MODULE); kfree(ugdb); } static struct pid *get_next_pid(struct pid *main, struct pid *curr) { struct task_struct *task; struct sighand_struct *sighand; struct pid *next = NULL; rcu_read_lock(); /* * If task/sighand is NULL we return NULL. This is fine if * the caller is get_first_pid(), we should abort attaching. * * But this can also happen if curr was already attached, * and this is wrong. Fortunately, this is very unlikely * case. The attached sub-thread can't pass ->report_death, * if it was reaped the caller of release_task() must be * ptracer who re-parented this thread. */ task = pid_task(curr, PIDTYPE_PID); if (!task) goto unlock_rcu; // XXX: we need lock_task_sighand() but it is not exported, // so we ran race with de_thread(). sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); for (;;) { task = next_thread(task); // XXX: if main is not leader we can race with exec. if (task_pid(task) == main) break; if (!task->exit_state) { next = get_pid(task_pid(task)); break; } } spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); return next; } static struct pid *get_first_pid(struct pid *main) { struct task_struct *leader; rcu_read_lock(); leader = pid_task(main, PIDTYPE_PID); if (leader && leader->exit_state) leader = NULL; rcu_read_unlock(); /* * The group-leader is alive, try to attach. If it exits * before utrace_set_events(), get_first_pid() will be * called again and it will notice ->exit_state != 0. */ if (leader) return get_pid(main); /* * Try to find the live sub-thread. If the whole group * is dead it returns NULL and the caller aborts. */ return get_next_pid(main, main); } static int ugdb_attach_all_threads(struct ugdb *ugdb, struct ugdb_process *process, struct pid *main_pid) { struct ugdb_thread *thread; struct pid *curr_pid; mutex_lock(&ugdb->u_mutex); for (;;) { curr_pid = get_first_pid(main_pid); if (!curr_pid) goto abort; thread = ugdb_attach_thread(process, curr_pid); put_pid(curr_pid); if (IS_ERR(thread)) goto abort; if (thread) break; } for (;;) { struct pid *next_pid; next_pid = get_next_pid(main_pid, curr_pid); if (!next_pid) break; thread = ugdb_attach_thread(process, next_pid); put_pid(next_pid); if (IS_ERR(thread)) goto abort; if (!thread) continue; curr_pid = next_pid; } mutex_unlock(&ugdb->u_mutex); return 0; abort: mutex_unlock(&ugdb->u_mutex); return -1; } static int ugdb_attach(struct ugdb *ugdb, int pid_nr) { struct pid *main_pid; struct ugdb_process *process; int err; // XXX: check if exists // XXX: check if group leader ? err = -ESRCH; main_pid = find_get_pid(pid_nr); if (!main_pid) goto out; err = -ENOMEM; process = ugdb_create_process(ugdb, pid_nr); if (!process) goto free_pid; err = ugdb_attach_all_threads(ugdb, process, main_pid); if (err) ugdb_destroy_process(process); free_pid: put_pid(main_pid); out: return err; } static struct ugdb_process *ugdb_find_process(struct ugdb *ugdb, int pid) { struct ugdb_process *process; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (process->p_pid == pid) return process; } return NULL; } static struct ugdb_thread *ugdb_find_thread(struct ugdb *ugdb, int pid, int tid) { struct ugdb_process *process; struct ugdb_thread *thread; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (!tid || thread->t_tid == tid) return thread; } if (pid) break; } return NULL; } static int ugdb_detach(struct ugdb *ugdb, int pid) { struct ugdb_process *process = ugdb_find_process(ugdb, pid); if (!process) return -1; ugdb_destroy_process(process); return 0; } #define CUR_TINFO_END ((struct ugdb_thread *)1) static struct ugdb_thread *ugdb_advance_tinfo(struct ugdb *ugdb) { struct ugdb_thread *cur, *nxt; struct ugdb_process *process; cur = ugdb->u_cur_tinfo; if (cur == CUR_TINFO_END) { ugdb->u_cur_tinfo = NULL; return NULL; } if (!cur) { list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { cur = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } if (!cur) return NULL; } process = cur->t_process; if (list_is_last(&cur->t_threads, &process->p_threads)) { nxt = CUR_TINFO_END; list_for_each_entry_continue(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { nxt = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } } else { nxt = list_first_entry(&cur->t_threads, struct ugdb_thread, t_threads); } ugdb->u_cur_tinfo = nxt; return cur; } // ----------------------------------------------------------------------------- static bool ugdb_add_stopped(struct ugdb_thread *thread, int stop_event) { struct ugdb *ugdb = thread->t_ugdb; bool ret = false; ugdb_ck_stopped(ugdb); spin_lock(&ugdb->u_slock); if (stop_event == T_EV_NONE) { if (WARN_ON(thread->t_stop_state & T_STOP_ACK)) goto unlock; if (WARN_ON(!list_empty(&thread->t_stopped))) goto unlock; /* raced with ugdb_cont_thread() */ if (!(thread->t_stop_state & T_STOP_REQ)) goto unlock; } if (thread->t_stop_state & T_STOP_ACK) { if (thread->t_stop_state & T_STOP_STOPPED) /* * Alas, we can't report this event. We already * reported T00 and there is no way to inform gdb * the state of tracee was changed. */ goto unlock; } else { WARN_ON(thread->t_stop_state & T_STOP_STOPPED); thread->t_stop_state |= T_STOP_ACK; list_add_tail(&thread->t_stopped, &ugdb->u_stopped); if (ugdb->u_stop_state == U_STOP_IDLE) { ugdb->u_stop_state = U_STOP_PENDING; wake_up_all(&ugdb->u_wait); } } thread->t_stop_event = stop_event; ret = true; unlock: spin_unlock(&ugdb->u_slock); return ret; } static void ugdb_process_exit(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; int status; BUG_ON(!thread_alive(thread)); ugdb_del_stopped(ugdb, thread); mark_thread_dead(thread); // XXX: OOPS, we can't read ->signal->group_exit_code !!! status = current->exit_code; if (ugdb_add_stopped(thread, T_EV_EXIT | status)) return; WARN_ON(1); } static int ugdb_stop_thread(struct ugdb_thread *thread, bool all) { struct ugdb *ugdb = thread->t_ugdb; int err; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); if (thread->t_stop_state != T_STOP_RUN) { if (!all || (thread->t_stop_state & T_STOP_ALL)) return 0; /* * Otherwise we should set T_STOP_ALL anyway, * * (gdb) interrupt & * (gbd) interrupt -a & * * to ensure -a actually works if it races with clone. */ } err = -EALREADY; spin_lock(&ugdb->u_slock); if (thread->t_stop_state == T_STOP_RUN) { thread->t_stop_state = T_STOP_REQ; err = 0; } /* * We hold ugdb->u_mutex, we can't race with ugdb_report_clone(). * ugdb->u_slock protects us against ugdb_add_stopped(). We can * change ->t_stop_state even if we did not initiate this stop. */ if (all) thread->t_stop_state |= T_STOP_ALL; spin_unlock(&ugdb->u_slock); if (err) return 0; // XXX: we don't do UTRACE_STOP! this means we can't // stop TASK_STOPEED task. Need to discuss jctl issues. // if we do UTRACE_STOP we should call ugdb_add_stopped(). ugdb_set_events(thread, UTRACE_EVENT(QUIESCE)); err = ugdb_control(thread, UTRACE_INTERRUPT); if (err && err != -EINPROGRESS) return err; return 1; } static int ugdb_cont_thread(struct ugdb_thread *thread, bool all, int t_step) { struct ugdb *ugdb = thread->t_ugdb; int ret; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); // XXX: gdb shouldn't explicitly cont an unreported thread WARN_ON(!all && !(thread->t_stop_state & T_STOP_STOPPED)); if (thread->t_stop_state == T_STOP_RUN) return 0; spin_lock(&ugdb->u_slock); /* * Nothing to do except clear the pending T_STOP_REQ. */ ret = 0; if (!(thread->t_stop_state & T_STOP_ACK)) goto set_run; /* * Alas. Thanks to remote protocol, we can't cont this * thread. We probably already sent the notification, we * can do nothing except ack that %Stop later in response * to vStopped. * * OTOH, gdb shouldn't send 'c' if this thread was not * reported as stopped. However, this means that gdb can * see the new %Stop:T00 notification after vCont;c:pX.-1, * it should handle this case correctly anyway. I hope. * * If this stop was not initiated by gdb we should not * cancel it too, this event should be reported first. */ ret = -1; if (!(thread->t_stop_state & T_STOP_STOPPED)) goto unlock; ret = 1; list_del_init(&thread->t_stopped); set_run: thread->t_stop_state = T_STOP_RUN; unlock: spin_unlock(&ugdb->u_slock); if (ret >= 0) { unsigned long events = 0; enum utrace_resume_action action = UTRACE_RESUME; thread->t_step = t_step; if (t_step) { /* to correctly step over syscall insn */ events |= UTRACE_EVENT(SYSCALL_EXIT); action = UTRACE_SINGLESTEP; } // XXX: OK, this all is racy, and I do not see any // solution except: implement UTRACE_STOP_STICKY and // move this code up under the lock, or add // utrace_engine_ops->notify_stopped(). // 1. UTRACE_RESUME is racy, this is fixeable. // 2. we need utrace_barrier() to close the race // with the callback which is going to return // UTRACE_STOP, but: // a) we can deadlock (solveable) // b) in this case UTRACE_RESUME can race with // another stop initiated by tracee itself. ugdb_set_events(thread, events); ugdb_control(thread, action); } return ret; } static struct ugdb_thread *ugdb_next_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread = NULL; // XXX: temporary racy check WARN_ON(ugdb->u_stop_state == U_STOP_IDLE); spin_lock(&ugdb->u_slock); if (list_empty(&ugdb->u_stopped)) { ugdb->u_stop_state = U_STOP_IDLE; } else { ugdb->u_stop_state = U_STOP_SENT; thread = list_first_entry(&ugdb->u_stopped, struct ugdb_thread, t_stopped); thread->t_stop_state |= T_STOP_STOPPED; list_del_init(&thread->t_stopped); } spin_unlock(&ugdb->u_slock); return thread; } // ----------------------------------------------------------------------------- static bool ugdb_stop_pending(struct ugdb_thread *thread) { if (!(thread->t_stop_state & T_STOP_REQ)) return false; if (!(thread->t_stop_state & T_STOP_ACK)) return ugdb_add_stopped(thread, T_EV_NONE); return true; } static u32 ugdb_report_quiesce(u32 action, struct utrace_engine *engine, unsigned long event) { struct ugdb_thread *thread = engine->data; WARN_ON(!thread_alive(thread)); /* ensure SIGKILL can't race with stop/cont in progress */ if (event != UTRACE_EVENT(DEATH)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP; } return utrace_resume_action(action); } static int cont_signal(struct ugdb_thread *thread, struct k_sigaction *return_ka) { int signr = T_EV_DATA(thread->t_stop_event); siginfo_t *info = thread->t_siginfo; thread->t_siginfo = NULL; if (WARN_ON(!valid_signal(signr))) return 0; if (!signr) return signr; /* * Update the siginfo structure if the signal has changed. */ if (info->si_signo != signr) { info->si_signo = signr; info->si_errno = 0; info->si_code = SI_USER; info->si_pid = 0; info->si_uid = 0; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, info, current); signr = 0; } else { spin_lock_irq(¤t->sighand->siglock); *return_ka = current->sighand->action[signr - 1]; spin_unlock_irq(¤t->sighand->siglock); } return signr; } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info); static u32 ugdb_report_signal(u32 action, struct utrace_engine *engine, struct pt_regs *regs, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) { struct ugdb_thread *thread = engine->data; struct ugdb *ugdb = thread->t_ugdb; int signr; WARN_ON(!thread_alive(thread)); switch (utrace_signal_action(action)) { case UTRACE_SIGNAL_HANDLER: if (WARN_ON(thread->t_siginfo)) thread->t_siginfo = NULL; if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } /* Fall through */ default: if (orig_ka) break; /* * It was UTRACE_SIGNAL_REPORT, but another tracer has * changed utrace_report->result to deliver or stop. * Fall through. */ case UTRACE_SIGNAL_REPORT: if (!thread->t_siginfo) { /* UTRACE_INTERRUPT from ugdb_report_syscall_exit() */ if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } } else { if (WARN_ON(thread->t_siginfo != info)) return action; WARN_ON(T_EV_TYPE(thread->t_stop_event) != T_EV_SIGN); signr = cont_signal(thread, return_ka); if (signr) { /* * Consider: * * (gdb) signal SIG & * (gdb) interrupt * * We shouldn't miss the new stop request, so * we do not return from here. */ action = UTRACE_RESUME | UTRACE_SIGNAL_DELIVER; } } if (ugdb_stop_pending(thread)) return UTRACE_STOP | utrace_signal_action(action); if (thread->t_step) return UTRACE_SINGLESTEP | utrace_signal_action(action); return action; } WARN_ON(thread->t_siginfo); signr = info->si_signo; if (WARN_ON(!signr || !valid_signal(signr))) return action; if (wp_next_soft_trap(thread, info)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP | UTRACE_SIGNAL_IGN; return UTRACE_SINGLESTEP | UTRACE_SIGNAL_IGN; } if (sigismember(&ugdb->u_sig_ign, signr)) return action; if (ugdb_add_stopped(thread, T_EV_SIGN | signr)) { thread->t_siginfo = info; /* * Make sure the subsequent UTRACE_SIGNAL_REPORT clears * ->t_siginfo before return from get_signal_to_deliver(). */ if (utrace_control(current, engine, UTRACE_INTERRUPT)) WARN_ON(1); return UTRACE_STOP | UTRACE_SIGNAL_IGN; } /* * We already reported T00 to gdb. We can't change our state, * we are already stopped from gdb pov. Push back this signal * to report it later, after "continue". * * Not multitrace-friendly. */ return UTRACE_STOP | UTRACE_SIGNAL_REPORT | UTRACE_SIGNAL_HOLD; } static u32 ugdb_report_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { struct ugdb_thread *thread = engine->data; if (thread->t_step) return UTRACE_INTERRUPT; printk(KERN_INFO "ugdb: unexpected SYSCALL_EXIT\n"); return action; } static bool is_already_attached(struct ugdb_process *process, struct task_struct *task) { struct ugdb_thread *thread; if (likely(!task_utrace_flags(task))) return false; /* * Currently there is no way to know if it was attached by us. * We can't trust utrace_attach_task(UTRACE_ATTACH_MATCH_OPS), * ugdb attaches without UTRACE_ATTACH_EXCLUSIVE. We have to * check every attached thread. * * This is really bad, but without multitracing this can only * happen in unlikely case right after ugdb_attach_all_threads(). */ list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_spid == task_pid(task)) return true; } return false; } static void ugdb_wp_clone(struct ugdb_thread *thread); static u32 ugdb_report_clone(u32 action, struct utrace_engine *engine, unsigned long clone_flags, struct task_struct *task) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; struct ugdb_thread *new_thread; WARN_ON(!thread_alive(thread)); if (!(clone_flags & CLONE_THREAD)) goto out; mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; /* * This can only happen if we raced with ugdb_attach() which * could attach both current and the new PF_STARTING child. */ if (unlikely(is_already_attached(process, task))) goto unlock; new_thread = ugdb_attach_thread(process, task_pid(task)); BUG_ON(!new_thread); if (WARN_ON(IS_ERR(new_thread))) goto unlock; if (thread->t_stop_state & T_STOP_ALL) ugdb_stop_thread(new_thread, false); else ugdb_wp_clone(new_thread); unlock: mutex_unlock(&ugdb->u_mutex); out: return utrace_resume_action(action); } static u32 ugdb_report_death(struct utrace_engine *engine, bool group_dead, int signal) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; WARN_ON(!thread_alive(thread)); mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; if (ugdb->u_cur_hg == thread) ugdb->u_cur_hg = NULL; if (ugdb->u_cur_hc == thread) ugdb->u_cur_hc = NULL; if (ugdb->u_cur_tinfo == thread) ugdb_advance_tinfo(ugdb); if (list_is_singular(&process->p_threads)) ugdb_process_exit(thread); else ugdb_destroy_thread(thread); unlock: mutex_unlock(&ugdb->u_mutex); return UTRACE_DETACH; } static const struct utrace_engine_ops ugdb_utrace_ops = { .report_quiesce = ugdb_report_quiesce, .report_signal = ugdb_report_signal, .report_syscall_exit = ugdb_report_syscall_exit, .report_clone = ugdb_report_clone, .report_death = ugdb_report_death, }; // ----------------------------------------------------------------------------- static inline int pb_size(struct pbuf *pb) { return pb->cur - pb->buf; } static inline int pb_room(struct pbuf *pb) { return pb->buf + BUFFER_SIZE - pb->cur; } static inline void pb_putc(struct pbuf *pb, char c) { if (WARN_ON(pb->cur >= pb->buf + BUFFER_SIZE)) return; *pb->cur++ = c; } static void pb_memcpy(struct pbuf *pb, const void *data, int size) { if (WARN_ON(size > pb_room(pb))) return; memcpy(pb->cur, data, size); pb->cur += size; } static inline void pb_puts(struct pbuf *pb, const char *s) { pb_memcpy(pb, s, strlen(s)); } static inline void pb_putb(struct pbuf *pb, unsigned char val) { static char hex[] = "0123456789abcdef"; pb_putc(pb, hex[(val & 0xf0) >> 4]); pb_putc(pb, hex[(val & 0x0f) >> 0]); } static void pb_putbs(struct pbuf *pb, const char *data, int size) { while (size--) pb_putb(pb, *data++); } static inline void __pb_start(struct pbuf *pb, char pref) { WARN_ON(pb->pkt); pb_putc(pb, pref); pb->pkt = pb->cur; } static inline void pb_start(struct pbuf *pb) { return __pb_start(pb, '$'); } static inline void pb_cancel(struct pbuf *pb) { if (WARN_ON(!pb->pkt)) return; pb->cur = pb->pkt - 1; pb->pkt = NULL; } static void pb_end(struct pbuf *pb) { unsigned char csm = 0; char *pkt = pb->pkt; pb->pkt = NULL; if (WARN_ON(!pkt)) return; while (pkt < pb->cur) { /* pb_qfer() can write '%' */ WARN_ON(*pkt == '$' || *pkt == '#'); csm += (unsigned char)*pkt++; } pb_putc(pb, '#'); pb_putb(pb, csm); } static inline void pb_packs(struct pbuf *pb, const char *s) { pb_start(pb); pb_puts(pb, s); pb_end(pb); } static void __attribute__ ((format(printf, 3, 4))) __pb_format(struct pbuf *pb, bool whole_pkt, const char *fmt, ...) { int room = pb_room(pb), size; va_list args; if (whole_pkt) pb_start(pb); va_start(args, fmt); size = vsnprintf(pb->cur, room, fmt, args); va_end(args); if (WARN_ON(size > room)) return; pb->cur += size; if (whole_pkt) pb_end(pb); } #define pb_printf(pb, args...) __pb_format((pb), false, args) #define pb_packf(pb, args...) __pb_format((pb), true, args) static int pb_qfer(struct pbuf *pb, const void *_data, int len, bool more) { const unsigned char *data = _data; int i; if (pb_room(pb) < 3 + len * 2) { WARN_ON(1); return -EOVERFLOW; } pb_start(pb); pb_putc(pb, more ? 'm' : 'l'); for (i = 0; i < len; ++i) { unsigned char c = data[i]; if (c == '$' || c == '#' || c == '}' || c == '*') { pb_putc(pb, '}'); c ^= 0x20; } pb_putc(pb, c); } pb_end(pb); return 0; } // XXX: improve me! static inline int pb_max_bs_size(struct pbuf *pb) { int size = pb_room(pb) - 4; return size > 0 ? size / 2 : 0; } static inline void *pb_alloc_bs(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < 2 * size + 4)) return NULL; return pb->cur + size + 1; } static inline void *pb_alloc_tmp(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < size)) return NULL; return pb->cur + BUFFER_SIZE - size; } static inline void pb_flush(struct pbuf *pb, int size) { int keep = pb_size(pb) - size; if (keep) memmove(pb->buf, pb->buf + size, keep); pb->cur -= size; } static int pb_copy_to_user(struct pbuf *pb, char __user *ubuf, int size) { int copy = min(size, pb_size(pb)); if (!copy) return -EAGAIN; if (o_remote_debug) printk(KERN_INFO "<= %.*s\n", min(copy, 64), pb->buf); if (copy_to_user(ubuf, pb->buf, copy)) return -EFAULT; pb_flush(pb, copy); return copy; } // ----------------------------------------------------------------------------- static typeof(access_process_vm) *u_access_process_vm; static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static inline int ugdb_readmeam(struct ugdb *ugdb, unsigned long addr, int size, void *kbuf) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) return ret; ret = u_access_process_vm(task, addr, kbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; return ret; } #define WP_CHANGED 0 struct wp { unsigned long flags; struct list_head wp_node; unsigned long addr; int size; unsigned long data[0]; }; static void p_wp_free(struct p_wp *p_wp) { struct wp *wp, *n; list_for_each_entry_safe(wp, n, &p_wp->wp_list, wp_node) { p_wp->wp_cnt -= 1; p_wp->wp_mem -= wp->size; kfree(wp); } WARN_ON(p_wp->wp_cnt || p_wp->wp_mem); } static inline struct wp *wp_alloc(struct ugdb *ugdb, unsigned long addr, int size) { struct wp *wp; wp = kmalloc(sizeof(*wp) + size, GFP_KERNEL); if (!wp) return wp; wp->flags = 0; wp->addr = addr; wp->size = size; // XXX: and what should we do if it fails? ugdb_readmeam(ugdb, addr, size, wp->data); return wp; } static inline struct wp *wp_find(struct p_wp *p_wp, unsigned long addr, int size) { struct wp *wp; list_for_each_entry(wp, &p_wp->wp_list, wp_node) if (wp->addr == addr && wp->size == size) return wp; return NULL; } #define WP_MAX_CNT 64 #define WP_MAX_MEM 4096 #define WP_MAX_LEN 1024 static const char *handle_z(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; bool insert; int type; struct ugdb_process *process; struct p_wp *p_wp; struct wp *wp; insert = (*cmd++ == 'Z'); if (sscanf(cmd, "%d,%lx,%lx", &type, &addr, &size) != 3) return "E01"; if (type != 2) return ""; if (size > WP_MAX_LEN) return "E01"; process = NULL; mutex_lock(&ugdb->u_mutex); if (ugdb->u_cur_hg) process = ugdb->u_cur_hg->t_process; mutex_unlock(&ugdb->u_mutex); if (!process) return "E01"; p_wp = &process->p_wp; wp = wp_find(p_wp, addr, size); if (insert) { if (wp) return "E01"; if (!size || size > WP_MAX_LEN || p_wp->wp_cnt + 1 > WP_MAX_CNT || p_wp->wp_mem + size > WP_MAX_MEM) return "E01"; wp = wp_alloc(ugdb, addr, size); if (!wp) return "E01"; down_write(&p_wp->wp_sem); list_add_tail(&wp->wp_node, &p_wp->wp_list); up_write(&p_wp->wp_sem); p_wp->wp_cnt += 1; p_wp->wp_mem += size; } else { if (!wp) return "E01"; down_write(&p_wp->wp_sem); list_del(&wp->wp_node); up_write(&p_wp->wp_sem); if (test_bit(WP_CHANGED, &wp->flags)) { struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_wp.wp_cur == wp) thread->t_wp.wp_cur = NULL; } mutex_unlock(&ugdb->u_mutex); } p_wp->wp_cnt -= 1; p_wp->wp_mem -= size; kfree(wp); } return "OK"; } #define WP_NO_WATCH -1ul static unsigned long get_cur_watch(struct ugdb_thread *thread) { struct wp *wp = thread->t_wp.wp_cur; if (likely(!wp)) return WP_NO_WATCH; thread->t_wp.wp_cur = NULL; clear_bit(WP_CHANGED, &wp->flags); return wp->addr; } static bool has_watchpoints(struct ugdb_thread *thread) { return unlikely(!list_empty(&thread->t_process->p_wp.wp_list)); } static int memcmp_user(void *kp, void __user *up, int sz) { unsigned char data[64]; while (sz) { int size = sizeof(data); if (size > sz) size = sz; if (copy_from_user(data, up, size)) ; if (memcmp(data, kp, size)) return 1; up += size; kp += size; sz -= size; } return 0; } static bool check_one_wp(struct wp *wp) { void __user *up = (void __user*)wp->addr; if (test_bit(WP_CHANGED, &wp->flags)) return false; if (!memcmp_user(wp->data, up, wp->size)) return false; if (test_and_set_bit(WP_CHANGED, &wp->flags)) return false; copy_from_user(wp->data, up, wp->size); return true; } static bool check_watchpoints(struct ugdb_thread *thread) { struct p_wp *p_wp = &thread->t_process->p_wp; struct wp *wp; bool ret = false; down_read(&p_wp->wp_sem); list_for_each_entry(wp, &p_wp->wp_list, wp_node) { ret = check_one_wp(wp); if (ret) { thread->t_wp.wp_cur = wp; break; } } up_read(&p_wp->wp_sem); return ret; } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info) { if (!has_watchpoints(thread)) return false; if (check_watchpoints(thread)) return false; return info->si_signo == SIGTRAP && thread->t_step == T_STEP_SOFT && // XXX: this filters out do_int3() only. // XXX: this is not right, we probably need // to check trap_no == 1, but then we need // unexported user_single_step_siginfo() for // ugdb_report_signal(). current->thread.trap_no != 3; } static void ugdb_wp_clone(struct ugdb_thread *thread) { if (has_watchpoints(thread)) { thread->t_step = T_STEP_SOFT; ugdb_set_events(thread, UTRACE_EVENT(SYSCALL_EXIT)); ugdb_control(thread, UTRACE_SINGLESTEP); } } // ----------------------------------------------------------------------------- // XXX: include/gdb/signals.h:target_signal // incomplete: 7, 29, rt? static int to_gdb_sigmap[] = { [SIGHUP] = 1, [SIGINT] = 2, [SIGQUIT] = 3, [SIGILL] = 4, [SIGTRAP] = 5, [SIGABRT] = 6, [SIGIOT] = 0, /* ??? */ [SIGBUS] = 10, [SIGFPE] = 8, [SIGKILL] = 9, [SIGUSR1] = 30, [SIGSEGV] = 11, [SIGUSR2] = 31, [SIGPIPE] = 13, [SIGALRM] = 14, [SIGTERM] = 15, [SIGSTKFLT] = 0, /* ??? */ [SIGCHLD] = 20, [SIGCONT] = 19, [SIGSTOP] = 17, [SIGTSTP] = 18, [SIGTTIN] = 21, [SIGTTOU] = 22, [SIGURG] = 16, [SIGXCPU] = 24, [SIGXFSZ] = 25, [SIGVTALRM] = 26, [SIGPROF] = 27, [SIGWINCH] = 28, [SIGIO] = 23, [SIGPWR] = 32, [SIGSYS] = 12, }; static int sig_to_gdb(unsigned sig) { if (sig < ARRAY_SIZE(to_gdb_sigmap) && to_gdb_sigmap[sig]) return to_gdb_sigmap[sig]; return sig; } static int sig_from_gdb(unsigned sig) { int i; // XXX: valid_signal() is wrong, gdb has its own idea // about signals. fix to_gdb_sigmap[]. if (!sig || !valid_signal(sig)) return 0; for (i = 0; i < ARRAY_SIZE(to_gdb_sigmap); i++) { if (to_gdb_sigmap[i] == sig) return i; } return sig; } static int ugdb_report_stopped(struct ugdb *ugdb, bool async) { struct ugdb_thread *thread; int pid, tid, event, data; unsigned long watch; struct pbuf *pb; char ex_r; mutex_lock(&ugdb->u_mutex); thread = ugdb_next_stopped(ugdb); if (!thread) goto unlock; event = thread->t_stop_event; watch = get_cur_watch(thread); WARN_ON(thread_alive(thread) != (T_EV_TYPE(event) != T_EV_EXIT)); pid = thread->t_process->p_pid; tid = thread->t_tid; unlock: mutex_unlock(&ugdb->u_mutex); if (!thread) return false; pb = &ugdb->u_pbuf; // XXX: damn, cleanup me... if (async) { __pb_start(pb, '%'); pb_puts(pb, "Stop:"); } else { pb_start(pb); } data = T_EV_DATA(event); switch (T_EV_TYPE(event)) { case T_EV_EXIT: if (data & 0xff) { data = sig_to_gdb(data & 0xff); ex_r = 'X'; } else { data >>= 8; ex_r = 'W'; } pb_printf(pb, "%c%x;process:%x", ex_r, data, pid); ugdb_destroy_process(thread->t_process); break; case T_EV_SIGN: case T_EV_NONE: pb_printf(pb, "T%02xthread:p%x.%x;", sig_to_gdb(data), pid, tid); if (unlikely(watch != WP_NO_WATCH)) pb_printf(pb, "watch:%lx;", watch); break; default: printk(KERN_INFO "ugdb: bad stop event %x\n", event); } pb_end(pb); return true; } const char *handle_vstopped(struct ugdb *ugdb) { if (ugdb->u_stop_state != U_STOP_SENT) return "E01"; if (ugdb_report_stopped(ugdb, false)) return NULL; return "OK"; } static const char *handle_thread_info(struct ugdb *ugdb, bool start) { struct ugdb_thread *thread; int pid = 0, tid; mutex_lock(&ugdb->u_mutex); if (start) ugdb_reset_tinfo(ugdb); else if (!ugdb->u_cur_tinfo) printk(KERN_INFO "ugdb: unexpected qsThreadInfo\n"); thread = ugdb_advance_tinfo(ugdb); if (thread) { pid = thread->t_process->p_pid; tid = thread->t_tid; } mutex_unlock(&ugdb->u_mutex); if (!pid) return start ? "E01" : "l"; pb_packf(&ugdb->u_pbuf, "mp%x.%x", pid, tid); return NULL; } static char *parse_xid(char *str, int *ppid, bool multi) { if (*str == '-') { str++; if (multi && *str++ == '1') *ppid = -1; else str = NULL; } else { char *cur = str; *ppid = simple_strtoul(cur, &str, 16); if (str == cur) str = NULL; } return str; } static char *parse_pid_tid(char *str, int *ppid, int *ptid, bool multi) { if (*str++ != 'p') return NULL; str = parse_xid(str, ppid, multi); if (!str) return NULL; if (*str++ != '.') return NULL; str = parse_xid(str, ptid, multi); if (!str) return NULL; return str; } static const char *handle_set_cur(struct ugdb *ugdb, char *cmd) { struct ugdb_thread **pthread; int pid, tid; switch (*cmd++) { case 'g': pthread = &ugdb->u_cur_hg; break; case 'c': pthread = &ugdb->u_cur_hc; break; default: goto err; } if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); *pthread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (*pthread) return "OK"; err: return "E01"; } static const char *handle_ck_alive(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; int pid = 0, tid; if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); thread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (thread) return "OK"; err: return "E01"; } static int parse_pid(char *str) { int pid; if (!parse_xid(str, &pid, false)) return 0; return pid; } static const char *handle_vattach(struct ugdb *ugdb, char *cmd) { int pid = parse_pid(cmd); if (pid && !ugdb_attach(ugdb, pid)) return "OK"; return "E01"; } static const char *handle_detach(struct ugdb *ugdb, char *cmd) { int pid; if (*cmd++ != ';') goto err; pid = parse_pid(cmd); if (pid && !ugdb_detach(ugdb, pid)) return "OK"; err: return "E01"; } typedef int (*each_func_t)(struct ugdb_thread *, void *); static int ugdb_do_each_thread(struct ugdb *ugdb, int pid, int tid, each_func_t func, void *arg) { struct ugdb_process *process; struct ugdb_thread *thread; int ret = -ESRCH; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid > 0 && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (tid > 0 && thread->t_tid != tid) continue; ret = func(thread, arg); if (ret) goto out; if (tid >= 0) break; } if (pid >= 0) break; } out: return ret; } static int thread_cont_signal(struct ugdb_thread *thread, int signr) { /* * T_STOP_STOPPED was set under ->u_slock so we can't race * with ugdb_add_stopped() and get the wrong t_stop_event. * And, the tracee never changes it after T_STOP_STOPPED. */ switch (T_EV_TYPE(thread->t_stop_event)) { case T_EV_SIGN: WARN_ON(!T_EV_DATA(thread->t_stop_event)); thread->t_stop_event = T_EV_SIGN | signr; break; default: if (!signr) break; // XXX: temporary hack, will be reported. // but perhaps this is what we want ??? kill_pid(thread->t_spid, signr, 0); break; } return 0; } static int ugdb_resume_thread(struct ugdb_thread *thread, int signr, bool step, bool all) { int t_step; int ret = 0; /* * Otherwise I do not know what to do if sig/step, and anyway * I don't think gdb can try to cont a thread which was not * reported as stopped. */ if (!(thread->t_stop_state & T_STOP_STOPPED)) return ret; ret = thread_cont_signal(thread, signr); if (ret < 0) return ret; t_step = 0; if (step) t_step = T_STEP_HARD; else if (has_watchpoints(thread)) t_step = T_STEP_SOFT; return ugdb_cont_thread(thread, all, t_step); } static const char *handle_c(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; const char *rc = "E01"; int gdbsig, signr = 0; bool step; step = (*cmd == 'S' || *cmd == 's'); switch (*cmd++) { case 'C': case 'S': gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) return rc; signr = sig_from_gdb(gdbsig); if (!signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); if (*cmd == ';') ++cmd; /* fall */ case 'c': case 's': if (!*cmd) break; printk(KERN_INFO "ugdb: $c ADDR not implemented\n"); return rc; break; } mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hc; if (!thread) goto unlock; if (ugdb_resume_thread(thread, signr, step, false) <= 0) goto unlock; /* Suprise: non-stop should not reply! */ rc = NULL; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } struct vcont_arg { int pid, tid; bool intr; int signr; bool step; }; static char* parse_vcont_arg(char *cmd, struct vcont_arg *vcont) { vcont->intr = false; vcont->signr = 0; switch (*cmd++) { case 't': vcont->intr = true; break; case 'S': vcont->signr = 1; case 's': vcont->step = true; break; case 'C': vcont->signr = 1; case 'c': vcont->step = false; break; default: goto err; } if (vcont->signr) { int gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) goto err; vcont->signr = sig_from_gdb(gdbsig); if (!vcont->signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); } vcont->pid = -1; vcont->tid = -1; if (*cmd == ':') { cmd = parse_pid_tid(cmd + 1, &vcont->pid, &vcont->tid, true); if (!cmd) goto err; } return cmd; err: return NULL; } static int do_vcont_thread(struct ugdb_thread *thread, void *arg) { struct vcont_arg *vcont = arg; unsigned long genctr; bool all; int err; genctr = thread->t_ugdb->u_genctr; if (genctr == thread->t_genctr) return 0; WARN_ON_ONCE(u_after(thread->t_genctr, genctr)); thread->t_genctr = genctr; all = (vcont->tid < 0); if (vcont->intr) err = ugdb_stop_thread(thread, all); else err = ugdb_resume_thread(thread, vcont->signr, vcont->step, all); if (err < 0) return err; return 0; } static const char *handle_vcont(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; switch (*cmd) { case ';': break; case '?': return "vCont;t;c;C;s;S"; default: return "E01"; } mutex_lock(&ugdb->u_mutex); ugdb->u_genctr++; while (*cmd) { struct vcont_arg vcont_arg; int err; if (*cmd++ != ';') goto unlock; cmd = parse_vcont_arg(cmd, &vcont_arg); if (!cmd) goto unlock; err = ugdb_do_each_thread(ugdb, vcont_arg.pid, vcont_arg.tid, do_vcont_thread, &vcont_arg); if (err) goto unlock; } rc = "OK"; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } static const char *handle_qpass_signals(struct ugdb *ugdb, char *cmd) { sigset_t *set = &ugdb->u_sig_ign; sigemptyset(set); while (*cmd) { char *end; int sig = simple_strtoul(cmd, &end, 16); if (cmd == end || *end != ';') return "E01"; cmd = end + 1; sig = sig_from_gdb(sig); if (!sig) // XXX: to_gdb_sigmap[] incomplete... // return "E01"; continue; sigaddset(set, sig); } return "OK"; } // ----------------------------------------------------------------------------- static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { struct ugdb_thread *thread; struct task_struct *task; int err; mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hg; if (!thread || !(thread->t_stop_state & T_STOP_STOPPED)) goto err; // XXX: u_cur_hg can't exit, we hold the mutex task = thread_to_task(thread); if (!task) goto err; for (;;) { if (fatal_signal_pending(current)) goto err; err = utrace_prepare_examine(task, thread->t_engine, exam); if (!err) break; if (err == -ESRCH) goto err; schedule_timeout_interruptible(1); } return task; err: mutex_unlock(&ugdb->u_mutex); return NULL; } // XXX: we hold the mutex in between, but only because we can't // use get_task_struct/put_task_struct. static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { // XXX: u_cur_hg can't exit, we hold the mutex struct ugdb_thread *thread = ugdb->u_cur_hg; struct task_struct *task = thread_to_task(thread); int ret = -ESRCH; if (task) ret = utrace_finish_examine(task, thread->t_engine, exam); mutex_unlock(&ugdb->u_mutex); return ret; } #define REGSET_GENERAL 0 #define REGSET_FP 1 #define MAX_REG_SIZE 16 struct gdbreg { unsigned short gdb_size, gdb_offs, rs_setno, usr_offs; }; // gdb/gdbserver/i387-fp.c:i387_fxsave struct gdb_i387_fxsave { unsigned short fctrl; unsigned short fstat; unsigned short ftag; unsigned short fop; unsigned int fioff; unsigned short fiseg; unsigned short pad1; unsigned int fooff; unsigned short foseg; unsigned short pad12; unsigned int mxcsr; unsigned int pad3; unsigned char st_space[128]; unsigned char xmm_space[256]; }; #define FPU__(mem) \ .rs_setno = REGSET_FP, \ .usr_offs = offsetof(struct gdb_i387_fxsave, mem) #define GEN__(mem) \ .rs_setno = REGSET_GENERAL, \ .usr_offs = offsetof(struct user_regs_struct, mem) /* generated from gdb/regformats/reg-x86-64-linux.dat */ struct gdbreg gdb_regmap_64[] = { [ 0] = { .gdb_size = 8, .gdb_offs = 0, GEN__(ax) }, [ 1] = { .gdb_size = 8, .gdb_offs = 8, GEN__(bx) }, [ 2] = { .gdb_size = 8, .gdb_offs = 16, GEN__(cx) }, [ 3] = { .gdb_size = 8, .gdb_offs = 24, GEN__(dx) }, [ 4] = { .gdb_size = 8, .gdb_offs = 32, GEN__(si) }, [ 5] = { .gdb_size = 8, .gdb_offs = 40, GEN__(di) }, [ 6] = { .gdb_size = 8, .gdb_offs = 48, GEN__(bp) }, [ 7] = { .gdb_size = 8, .gdb_offs = 56, GEN__(sp) }, [ 8] = { .gdb_size = 8, .gdb_offs = 64, GEN__(r8) }, [ 9] = { .gdb_size = 8, .gdb_offs = 72, GEN__(r9) }, [10] = { .gdb_size = 8, .gdb_offs = 80, GEN__(r10) }, [11] = { .gdb_size = 8, .gdb_offs = 88, GEN__(r11) }, [12] = { .gdb_size = 8, .gdb_offs = 96, GEN__(r12) }, [13] = { .gdb_size = 8, .gdb_offs = 104, GEN__(r13) }, [14] = { .gdb_size = 8, .gdb_offs = 112, GEN__(r14) }, [15] = { .gdb_size = 8, .gdb_offs = 120, GEN__(r15) }, [16] = { .gdb_size = 8, .gdb_offs = 128, GEN__(ip) }, [17] = { .gdb_size = 4, .gdb_offs = 136, GEN__(flags) }, [18] = { .gdb_size = 4, .gdb_offs = 140, GEN__(cs) }, [19] = { .gdb_size = 4, .gdb_offs = 144, GEN__(ss) }, [20] = { .gdb_size = 4, .gdb_offs = 148, GEN__(ds) }, [21] = { .gdb_size = 4, .gdb_offs = 152, GEN__(es) }, [22] = { .gdb_size = 4, .gdb_offs = 156, GEN__(fs) }, [23] = { .gdb_size = 4, .gdb_offs = 160, GEN__(gs) }, [24] = { .gdb_size = 10, .gdb_offs = 164, FPU__(st_space[0]) }, [25] = { .gdb_size = 10, .gdb_offs = 174, FPU__(st_space[16]) }, [26] = { .gdb_size = 10, .gdb_offs = 184, FPU__(st_space[32]) }, [27] = { .gdb_size = 10, .gdb_offs = 194, FPU__(st_space[48]) }, [28] = { .gdb_size = 10, .gdb_offs = 204, FPU__(st_space[64]) }, [29] = { .gdb_size = 10, .gdb_offs = 214, FPU__(st_space[80]) }, [30] = { .gdb_size = 10, .gdb_offs = 224, FPU__(st_space[96]) }, [31] = { .gdb_size = 10, .gdb_offs = 234, FPU__(st_space[112]) }, [32] = { .gdb_size = 4, .gdb_offs = 244, FPU__(fctrl) }, [33] = { .gdb_size = 4, .gdb_offs = 248, FPU__(fstat) }, [34] = { .gdb_size = 4, .gdb_offs = 252, FPU__(ftag) }, [35] = { .gdb_size = 4, .gdb_offs = 256, FPU__(fiseg) }, [36] = { .gdb_size = 4, .gdb_offs = 260, FPU__(fioff) }, [37] = { .gdb_size = 4, .gdb_offs = 264, FPU__(foseg) }, [38] = { .gdb_size = 4, .gdb_offs = 268, FPU__(fooff) }, [39] = { .gdb_size = 4, .gdb_offs = 272, FPU__(fop) }, [40] = { .gdb_size = 16, .gdb_offs = 276, FPU__(xmm_space[0]) }, [41] = { .gdb_size = 16, .gdb_offs = 292, FPU__(xmm_space[16]) }, [42] = { .gdb_size = 16, .gdb_offs = 308, FPU__(xmm_space[32]) }, [43] = { .gdb_size = 16, .gdb_offs = 324, FPU__(xmm_space[48]) }, [44] = { .gdb_size = 16, .gdb_offs = 340, FPU__(xmm_space[64]) }, [45] = { .gdb_size = 16, .gdb_offs = 356, FPU__(xmm_space[80]) }, [46] = { .gdb_size = 16, .gdb_offs = 372, FPU__(xmm_space[96]) }, [47] = { .gdb_size = 16, .gdb_offs = 388, FPU__(xmm_space[112]) }, [48] = { .gdb_size = 16, .gdb_offs = 404, FPU__(xmm_space[128]) }, [49] = { .gdb_size = 16, .gdb_offs = 420, FPU__(xmm_space[144]) }, [50] = { .gdb_size = 16, .gdb_offs = 436, FPU__(xmm_space[160]) }, [51] = { .gdb_size = 16, .gdb_offs = 452, FPU__(xmm_space[176]) }, [52] = { .gdb_size = 16, .gdb_offs = 468, FPU__(xmm_space[192]) }, [53] = { .gdb_size = 16, .gdb_offs = 484, FPU__(xmm_space[208]) }, [54] = { .gdb_size = 16, .gdb_offs = 500, FPU__(xmm_space[224]) }, [55] = { .gdb_size = 16, .gdb_offs = 516, FPU__(xmm_space[240]) }, [56] = { .gdb_size = 4, .gdb_offs = 532, FPU__(mxcsr) }, [57] = { .gdb_size = 8, .gdb_offs = 536, GEN__(orig_ax) }, }; #undef FPU__ #undef GEN__ static inline int rw_one_reg(struct task_struct *task, int regnum, unsigned char regval[], bool write) { const struct user_regset_view *view; const struct user_regset *rset; struct gdbreg *gdbreg; int err, count; view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: if (regnum >= ARRAY_SIZE(gdb_regmap_64)) return -EINVAL; gdbreg = gdb_regmap_64; count = sizeof(long); break; default: return -EIO; } gdbreg += regnum; rset = view->regsets + gdbreg->rs_setno; if (gdbreg->rs_setno != REGSET_GENERAL) count = gdbreg->gdb_size; if (WARN_ON(count > MAX_REG_SIZE)) return -EOVERFLOW; if (write) err = rset->set(task, rset, gdbreg->usr_offs, count, regval, NULL); else err = rset->get(task, rset, gdbreg->usr_offs, count, regval, NULL); return err ?: gdbreg->gdb_size; } static int ugdb_rw_one_reg(struct ugdb *ugdb, int regnum, unsigned char regval[], bool write) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto ret; ret = rw_one_reg(task, regnum, regval, write); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; ret: return ret; } // XXX: hex_to_bin() after 90378889 commit #include static int cap_hex_to_bin(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - '0'; ch = tolower(ch); if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; return -1; } static int unhex(char *cmd, int size) { char *bytes = cmd; while (size--) { int lo, hi; hi = cap_hex_to_bin(*cmd++); lo = cap_hex_to_bin(*cmd++); if (lo < 0 || hi < 0) return -EINVAL; *bytes++ = (hi << 4) | lo; } return 0; } static const char *handle_set_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned int reg; int skip; if (sscanf(cmd, "P%x=%n", ®, &skip) != 1) goto err; cmd += skip; len -= skip; if (len & 1) goto err; len /= 2; if (unhex(cmd, len)) goto err; if (ugdb_rw_one_reg(ugdb, reg, cmd, true) != len) goto err; return "OK"; err: return "E01"; } static const char *handle_get_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned char regval[MAX_REG_SIZE]; unsigned int reg; int skip, size; if (sscanf(cmd, "p%x%n", ®, &skip) != 1) goto err; if (len != skip) goto err; size = ugdb_rw_one_reg(ugdb, reg, regval, false); if (size < 0) goto err; pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regval, size); pb_end(&ugdb->u_pbuf); return NULL; err: return "E01"; } static int rw_one_regset(struct task_struct *task, int rsn, const struct user_regset_view *view, void *reg_mem, int reg_size, struct gdbreg *reg_map, int reg_cnt, void *gdb_mem, bool write) { const struct user_regset *rset = view->regsets + rsn; int err; if (write) { for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(reg_mem + reg_map->usr_offs, gdb_mem + reg_map->gdb_offs, reg_map->gdb_size); } err = rset->set(task, rset, 0, reg_size, reg_mem, NULL); } else { err = rset->get(task, rset, 0, reg_size, reg_mem, NULL); if (err) goto ret; for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(gdb_mem + reg_map->gdb_offs, reg_mem + reg_map->usr_offs, reg_map->gdb_size); } } ret: return err; } #define GDB_REGS_SIZE(regmap) \ (regmap[ARRAY_SIZE(regmap)-1].gdb_size + \ regmap[ARRAY_SIZE(regmap)-1].gdb_offs) struct regs_buf { unsigned char gdb_mem[1024]; union { struct user_regs_struct user_regs_struct; struct user_i387_struct user_i387_struct; }; }; static int ugdb_rw_all_regs(struct task_struct *task, struct regs_buf *regs_buf, bool write) { const struct user_regset_view *view; int ret; #define RW(rsn, user, rmap) \ rw_one_regset(task, rsn, view, \ ®s_buf->user, sizeof(regs_buf->user), \ rmap, ARRAY_SIZE(rmap), regs_buf->gdb_mem, \ write) view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: // XXX: even this needs fixup. There is no ->fs_base in gdb's set // of regs, it is wrongly initialized as 0 and putreg()->do_arch_prctl() // changes fs. Later, gdb seems to never use G if P works. ret = RW(REGSET_GENERAL, user_regs_struct, gdb_regmap_64); if (ret) break; // XXX: needs fixup, see i387_fxsave_to_cache/i387_cache_to_fxsave. // At least xfpregs_get() is safe even if result is not correct. if (!write) ret = RW(REGSET_FP, user_i387_struct, gdb_regmap_64); if (ret) break; ret = GDB_REGS_SIZE(gdb_regmap_64); break; default: ret = -EIO; } #undef RW return ret; } static const char *handle_get_all_regs(struct ugdb *ugdb) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, false); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; if (size > sizeof(regs_buf->gdb_mem)) { WARN_ON(1); goto err; } if (pb_room(&ugdb->u_pbuf) < 3 + size * 2) { WARN_ON(1); goto err; } pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regs_buf->gdb_mem, size); pb_end(&ugdb->u_pbuf); ret = NULL; err: kfree(regs_buf); out: return ret; } static const char *handle_set_all_regs(struct ugdb *ugdb, char *cmd, int len) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; printk(KERN_INFO "XXX: $G command, why?\n"); cmd += 1; len -= 1; if (len & 1) goto out; len /= 2; if (unhex(cmd, len)) goto out; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; memcpy(regs_buf->gdb_mem, cmd, len); task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, true); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; WARN_ON(size != len); ret = "OK"; err: kfree(regs_buf); out: return ret; } static typeof(access_process_vm) *u_access_process_vm; static const char *handle_readmem(struct ugdb *ugdb, char *cmd) { struct utrace_examiner exam; struct task_struct *task; unsigned long addr, size; unsigned char *mbuf; int copied; if (sscanf(cmd, "m%lx,%lx", &addr, &size) != 2) goto err; size = min_t(unsigned long, size, pb_max_bs_size(&ugdb->u_pbuf)); if (!size) goto err; mbuf = pb_alloc_bs(&ugdb->u_pbuf, size); if (WARN_ON(!mbuf)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; copied = u_access_process_vm(task, addr, mbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (copied > 0 ) { pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, mbuf, copied); pb_end(&ugdb->u_pbuf); return NULL; } err: return "E01"; } static const char *handle_writemem(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; unsigned int skip, written; struct utrace_examiner exam; struct task_struct *task; if (sscanf(cmd, "M%lx,%lx:%n", &addr, &size, &skip) != 2) goto err; cmd += skip; len -= skip; if (len != 2*size || !size) goto err; if (unhex(cmd, size)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; written = u_access_process_vm(task, addr, cmd, size, 1); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (written == size) return "OK"; err: return "E01"; } static int ugdb_siginfo_rw(struct ugdb *ugdb, siginfo_t *info, bool write) { struct task_struct *task; struct utrace_examiner exam; struct sighand_struct *sighand; siginfo_t *t_siginfo; int ret = -EINVAL; /* * ugdb_prepare_examine() is overkill, but otherwise we can't * assume task_is_traced(), and this is what ensures we can * safely read/write ->t_siginfo which points to task's stack. */ task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto out; /* OK, task_struct can't go away, but ->sighand can. */ rcu_read_lock(); sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); if (!task_is_traced(task)) goto unlock_siglock; t_siginfo = ugdb->u_cur_hg->t_siginfo; if (!t_siginfo) goto unlock_siglock; if (write) *t_siginfo = *info; else *info = *t_siginfo; ret = 0; unlock_siglock: spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); ugdb_finish_examine(ugdb, &exam); out: return ret; } static const char *handle_siginfo_read(struct ugdb *ugdb, char *cmd) { unsigned int off, len; siginfo_t info; if (sscanf(cmd, "%x,%x", &off, &len) != 2) goto err; if (off >= sizeof(info)) goto err; if (len > sizeof(info) || off + len > sizeof(info)) len = sizeof(info) - off; if (ugdb_siginfo_rw(ugdb, &info, false)) goto err; if (pb_qfer(&ugdb->u_pbuf, &info + off, len, (off + len < sizeof(info)))) goto err; // XXX: Oh. we also need x86_siginfo_fixup(). how ugly. return NULL; err: return "E01"; } // ----------------------------------------------------------------------------- #define EQ(cmd, str) \ (strncmp((cmd), (str), sizeof(str)-1) ? false : \ ((cmd) += sizeof(str)-1, true)) static const char *handle_qfer(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; if (EQ(cmd, "siginfo:")) { if (EQ(cmd, "read::")) rc = handle_siginfo_read(ugdb, cmd); } return rc; } static void handle_command(struct ugdb *ugdb, char *cmd, int len) { struct pbuf *pb = &ugdb->u_pbuf; const char *rc = ""; switch (cmd[0]) { case '!': case '?': rc = "OK"; break; case 'H': rc = handle_set_cur(ugdb, cmd + 1); break; case 'T': rc = handle_ck_alive(ugdb, cmd + 1); break; case 'D': rc = handle_detach(ugdb, cmd + 1); break; case 'g': rc = handle_get_all_regs(ugdb); break; case 'G': rc = handle_set_all_regs(ugdb, cmd, len); break; case 'p': rc = handle_get_reg(ugdb, cmd, len); break; case 'P': rc = handle_set_reg(ugdb, cmd, len); break; case 'm': rc = handle_readmem(ugdb, cmd); break; case 'M': rc = handle_writemem(ugdb, cmd, len); break; case 'C': case 'c': case 'S': case 's': rc = handle_c(ugdb, cmd); break; case 'z': case 'Z': rc = handle_z(ugdb, cmd, len); break; case 'q': if (EQ(cmd, "qSupported")) { if (!strstr(cmd, "multiprocess+")) { printk(KERN_INFO "ugdb: can't work without multiprocess\n"); ugdb->u_err = -EPROTONOSUPPORT; } pb_packf(&ugdb->u_pbuf, "PacketSize=%x;%s", PACKET_SIZE, "QStartNoAckMode+;QNonStop+;multiprocess+;" "QPassSignals+;qXfer:siginfo:read+"); rc = NULL; } else if (EQ(cmd, "qfThreadInfo")) { rc = handle_thread_info(ugdb, true); } else if (EQ(cmd, "qsThreadInfo")) { rc = handle_thread_info(ugdb, false); } else if (EQ(cmd, "qXfer:")) { rc = handle_qfer(ugdb, cmd); } else if (EQ(cmd, "qTStatus")) { rc = "T0"; } break; case 'Q': if (EQ(cmd, "QStartNoAckMode")) { ugdb->u_no_ack = true; rc = "OK"; } else if (EQ(cmd, "QNonStop:")) { if (*cmd != '1') { printk(KERN_INFO "ugdb: all-stop is not implemented.\n"); ugdb->u_err = -EPROTONOSUPPORT; } rc = "OK"; } else if (EQ(cmd, "QPassSignals:")) { rc = handle_qpass_signals(ugdb, cmd); } break; case 'v': if (EQ(cmd, "vAttach;")) { rc = handle_vattach(ugdb, cmd); } else if (EQ(cmd, "vStopped")) { rc = handle_vstopped(ugdb); } else if (EQ(cmd, "vCont")) { rc = handle_vcont(ugdb, cmd); } break; default: ; } if (rc) pb_packs(pb, rc); } static void process_commands(struct ugdb *ugdb) { char *cmds = ugdb->u_cbuf; int todo = ugdb->u_clen; if (o_remote_debug) printk(KERN_INFO "=> %.*s\n", ugdb->u_clen, ugdb->u_cbuf); while (todo) { char first; char *c_cmd, *c_end; int c_len; first = *cmds++; todo--; switch (first) { default: printk(KERN_INFO "XXX: unknown chr %02x\n", first); pb_putc(&ugdb->u_pbuf, '-'); break; case '-': printk(KERN_INFO "XXX: got NACK!\n"); ugdb->u_err = -EPROTO; case '+': break; case 0x3: printk(KERN_INFO "XXX: unexpected CTRL-C\n"); break; case '$': c_cmd = cmds; c_end = strnchr(c_cmd, todo, '#'); c_len = c_end ? c_end - cmds : -1; if (c_len < 0 || todo < c_len + 3) { printk(KERN_INFO "XXX: can't find '#cs'\n"); ++todo; --cmds; goto out; } // XXX: verify checksum ? todo -= c_len + 3; cmds += c_len + 3; *c_end = 0; if (!ugdb->u_no_ack) pb_putc(&ugdb->u_pbuf, '+'); handle_command(ugdb, c_cmd, c_len); } } out: ugdb->u_clen = todo; if (todo && cmds > ugdb->u_cbuf) memmove(ugdb->u_cbuf, cmds, todo); } // ----------------------------------------------------------------------------- static int xxx_tinfo(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 0; mutex_lock(&ugdb->u_mutex); thread = ugdb_advance_tinfo(ugdb); if (thread) tid = thread->t_tid; mutex_unlock(&ugdb->u_mutex); return tid; } static int do_stop_thread(struct ugdb_thread *thread, void *arg) { ugdb_stop_thread(thread, arg != NULL); return 0; } static int do_cont_thread(struct ugdb_thread *thread, void *arg) { ugdb_cont_thread(thread, arg != NULL, false); return 0; } static int xxx_sc_threads(struct ugdb *ugdb, int tid, bool sc) { void *arg = NULL; int pid = 0; int ret; if (tid < 0) { pid = -tid; tid = -1; arg = (void*)1; } mutex_lock(&ugdb->u_mutex); ret = ugdb_do_each_thread(ugdb, pid, tid, sc ? do_stop_thread : do_cont_thread, arg); mutex_unlock(&ugdb->u_mutex); return ret; } static int xxx_stop(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, true); } static int xxx_cont(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, false); } static int xxx_get_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 1; if (ugdb->u_stop_state == U_STOP_IDLE) return -1; if (ugdb->u_stop_state == U_STOP_PENDING) tid = 1000; thread = ugdb_next_stopped(ugdb); if (!thread) return 0; return tid * thread->t_tid; } static int xxx_show_all(struct ugdb *ugdb) { struct ugdb_process *process; struct ugdb_thread *thread; printk(KERN_INFO "SHOW start ----------------------------------------\n"); mutex_lock(&ugdb->u_mutex); list_for_each_entry(process, &ugdb->u_processes, p_processes) { printk(KERN_INFO "PROC: %x\n", process->p_pid); list_for_each_entry(thread, &process->p_threads, t_threads) { printk(KERN_INFO " T: %x %p; %p %p\n", thread->t_tid, thread, thread->t_spid, pid_task(thread->t_spid, PIDTYPE_PID)); } } mutex_unlock(&ugdb->u_mutex); printk(KERN_INFO "SHOW end ----------------------------------------\n"); return 0; } static long ugdb_f_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ugdb *ugdb = file->private_data; // XXX: otherwise gdb->get_tty_state(TCGETS, TCSETS, TCFLSH) complains int ret = 0; // XXX: temporary debugging hooks, ignore. switch (cmd) { case 0x666 + 0: ret = ugdb_attach(ugdb, arg); break; case 0x666 + 1: ret = ugdb_detach(ugdb, arg); break; case 0x666 + 2: ret = xxx_tinfo(ugdb); break; case 0x666 + 3: ret = xxx_stop(ugdb, arg); break; case 0x666 + 4: ret = xxx_cont(ugdb, arg); break; case 0x666 + 5: ret = xxx_get_stopped(ugdb); break; case 0x666 + 6: ret = xxx_show_all(ugdb); break; } return ret; } static unsigned int ugdb_f_poll(struct file *file, poll_table *wait) { struct ugdb *ugdb = file->private_data; unsigned int mask; poll_wait(file, &ugdb->u_wait, wait); mask = (POLLOUT | POLLWRNORM); if (pb_size(&ugdb->u_pbuf) || ugdb->u_stop_state == U_STOP_PENDING) mask |= (POLLIN | POLLRDNORM); if (ugdb->u_err) mask |= POLLERR; return mask; } static ssize_t ugdb_f_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; struct pbuf *pb = &ugdb->u_pbuf; if (ugdb->u_err) return ugdb->u_err; if (ugdb->u_stop_state == U_STOP_PENDING) ugdb_report_stopped(ugdb, true); if (pb_size(pb) > count) { printk(KERN_INFO "XXX: short read %d %ld\n", pb_size(pb), count); } return pb_copy_to_user(pb, ubuf, count); } static ssize_t ugdb_f_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; if (ugdb->u_err) return ugdb->u_err; if (count > PACKET_SIZE - ugdb->u_clen) { count = PACKET_SIZE - ugdb->u_clen; printk("XXX: write(%ld,%d) enospc\n", count, ugdb->u_clen); if (1) return ugdb->u_err = -ENOSPC; } if (copy_from_user(ugdb->u_cbuf + ugdb->u_clen, ubuf, count)) return -EFAULT; ugdb->u_clen += count; process_commands(ugdb); return count; } static int ugdb_f_open(struct inode *inode, struct file *file) { nonseekable_open(inode, file); file->private_data = ugdb_create(); return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; } static int ugdb_f_release(struct inode *inode, struct file *file) { ugdb_destroy(file->private_data); return 0; } static const struct file_operations ugdb_f_ops = { .open = ugdb_f_open, .unlocked_ioctl = ugdb_f_ioctl, .poll = ugdb_f_poll, .read = ugdb_f_read, .write = ugdb_f_write, .release = ugdb_f_release, }; #include struct kallsyms_sym { const char *name; unsigned long addr; }; static int kallsyms_on_each_symbol_cb(void *data, const char *name, struct module *mod, unsigned long addr) { struct kallsyms_sym *sym = data; if (strcmp(name, sym->name)) return 0; sym->addr = addr; return 1; } // XXX: kallsyms_lookup_name() is not exported in 2.6.32 static bool lookup_unexported(void) { struct kallsyms_sym sym; sym.name = "access_process_vm"; if (!kallsyms_on_each_symbol(kallsyms_on_each_symbol_cb, &sym)) goto err; u_access_process_vm = (void*)sym.addr; return true; err: printk(KERN_ERR "ugdb: can't lookup %s\n", sym.name); return false; } #define PROC_NAME "ugdb" struct proc_dir_entry *ugdb_pde; static int __init ugdb_init(void) { if (!lookup_unexported()) return -ESRCH; ugdb_pde = proc_create(PROC_NAME, S_IFREG|S_IRUGO|S_IWUGO, NULL, &ugdb_f_ops); if (!ugdb_pde) return -EBADF; return 0; } static void __exit ugdb_exit(void) { remove_proc_entry(PROC_NAME, NULL); } MODULE_LICENSE("GPL"); module_init(ugdb_init); module_exit(ugdb_exit); From dbaukus at conveycomputer.com Thu Nov 11 20:20:27 2010 From: dbaukus at conveycomputer.com (dave baukus) Date: Thu, 11 Nov 2010 14:20:27 -0600 Subject: Utrace .report_jctl serialization issue Message-ID: <4CDC500B.2000702@conveycomputer.com> An HTML attachment was scrubbed... URL: From roland at redhat.com Thu Nov 11 20:25:59 2010 From: roland at redhat.com (Roland McGrath) Date: Thu, 11 Nov 2010 12:25:59 -0800 (PST) Subject: Utrace .report_jctl serialization issue In-Reply-To: dave baukus's message of Thursday, 11 November 2010 14:20:27 -0600 <4CDC500B.2000702@conveycomputer.com> References: <4CDC500B.2000702@conveycomputer.com> Message-ID: <20101111202559.0B366400DB@magilla.sf.frob.com> Please post in plain text. From dbaukus at conveycomputer.com Thu Nov 11 20:38:25 2010 From: dbaukus at conveycomputer.com (dave baukus) Date: Thu, 11 Nov 2010 14:38:25 -0600 Subject: Utrace .report_jctl serialization issue ? Message-ID: <4CDC5441.6000209@conveycomputer.com> Is a utrace engine with .report_jctl enabled suppose to handle do_notify_parent_cldstop(current, notify) processing for the last stopping task ? Or should it muck with task->ptrace to force tracehook_notify_jctl() to return a non-zero value ? I ask because I have a simple multi-threaded process with a utrace engine attached to the process group leader; .report_jctl is enabled. If I SIGTSTP the process, occasionally control is not returned to the shell. On my 2.6.32-44.2.el6 kernel this happens because when utrace_report_jctl() releases spin_unlock_irq(&task->sighand->siglock) it breaks serialization with sig->group_stop_count as required by do_signal_stop()'s do_notify_parent_cldstop(current, notify) processing. Let me explain: Consider the following code fragment from kernel/signal.c in function do_signal_stop(), released in rhel's 6x beta2 2.6.32-44.2.el6 kernel: 1707 /* 1708 * If there are no other threads in the group, or if there is 1709 * a group stop in progress and we are the last to stop, report 1710 * to the parent. When ptraced, every thread reports itself. 1711 */ 1712 notify = sig->group_stop_count == 1 ? CLD_STOPPED : 0; 1713 notify = tracehook_notify_jctl(notify, CLD_STOPPED); 1714 /* 1715 * tracehook_notify_jctl() can drop and reacquire siglock, so 1716 * we keep ->group_stop_count != 0 before the call. If SIGCONT 1717 * or SIGKILL comes in between ->group_stop_count == 0. 1718 */ 1719 if (sig->group_stop_count) { 1720 if (!--sig->group_stop_count) 1721 sig->flags = SIGNAL_STOP_STOPPED; 1722 current->exit_code = sig->group_exit_code; 1723 __set_current_state(TASK_STOPPED); 1724 } 1725 spin_unlock_irq(¤t->sighand->siglock); 1726 1727 if (notify) { 1728 read_lock(&tasklist_lock); 1729 do_notify_parent_cldstop(current, notify); 1730 read_unlock(&tasklist_lock); 1731 } 1732 1733 /* Now we don't run again until woken by SIGCONT or SIGKILL */ 1734 do { 1735 schedule(); 1736 } while (try_to_freeze()); 1737 1738 tracehook_finish_jctl(); 1739 current->exit_code = 0; 1740 1741 return 1; For the sake if discussion: * Let the task group have 2 tasks; therefore initially sig->group_stop_count == 2 * For both tasks task_ptrace(current) returns zero (see tracehook_notify_jctl() for why this matters) * Let task1 be the process group leader and let it be the first task to execute do_signal_stop() * Let task1 have a trace engine attached with .report_jctl enabled and let all engine ops be no-ops; they do nothing; simply return UTRACE_RESUME Now when I send a SIGTSTP via ctl-z on the terminal of this multi threaded process, the following can happen: * at line 1713 task1 calls tracehook_notify_jctl() with notify == 0 because sig->group_stop_count == 2 * Because task1 has a utrace engine with .report_jctl, it releases task->sighand->siglock in utrace_report_jctl() * Now task2 may enter do_signal_stop() with the task->sighand->siglock held. * For task2 sig->group_stop_count == 2 is still true because task1 is either off executing utrace code or it is waiting on task->sighand->siglock held by task2; task1 has not executed line 1720 * For task2 because sig->group_stop_count == 2 and because tracehook_notify_jctl(notify, CLD_STOPPED) returns zero, notify == 0 * Therefore when task2 executes line 1727 do_notify_parent_cldstop() is not executed. * After task2 releases the lock, task1 continues, but unfortunately because when it was setting the "notify" cookie sig->group_stop_count == 2 and tracehook_notify_jctl(notify, CLD_STOPPED) returned zero because notify was initially zero and task_ptrace(current) returned zero. * Therefore for task1, after tracehook_notify_jctl(), notify == 0 * Finally, when task1 executes line 1727 do_notify_parent_cldstop() is not executed. The result is a control-z that does not return control to the parent because line 1729 was never executed. One possible fix is to re-examine sig->group_stop_count after tracehook_notify_jctl() with something like: notify = notify ?: sig->group_stop_count == 1 ? CLD_STOPPED : 0; From roland at redhat.com Thu Nov 11 20:53:51 2010 From: roland at redhat.com (Roland McGrath) Date: Thu, 11 Nov 2010 12:53:51 -0800 (PST) Subject: Utrace .report_jctl serialization issue ? In-Reply-To: dave baukus's message of Thursday, 11 November 2010 14:38:25 -0600 <4CDC5441.6000209@conveycomputer.com> References: <4CDC5441.6000209@conveycomputer.com> Message-ID: <20101111205351.6C09C400DB@magilla.sf.frob.com> > Is a utrace engine with .report_jctl enabled suppose to handle > do_notify_parent_cldstop(current, notify) processing for the last > stopping task ? Or should it muck with task->ptrace to force > tracehook_notify_jctl() to return a non-zero value ? I can't figure out exactly how to construe this as a question about the utrace API. The documented API is that each thread gets a report_jctl callback, and the @notify argument is zero in all threads but one. > I ask because I have a simple multi-threaded process with a utrace engine > attached to the process group leader; .report_jctl is enabled. Do you mean the thread_group leader of one process in the process group? Or do you mean multiple utrace engines, one per thread, all in the process whose pid==pgid (that's what "process group leader" means in POSIX)? > If I SIGTSTP the process, occasionally control is not returned to the > shell. That sounds like a kernel bug. There should be nothing your report_jctl callback could do (assuming it doesn't send more signals itself) that affects the normal job control semantics. The kernels that are appropriate to discuss here are upstream kernels with the current utrace patches applied (i.e. what you get in the current utrace-ptrace git branch), or the most recent Fedora kernels that should include that same code. The code in question might well be the same in RHEL6 kernels, but RHEL issues need to be addressed through the proper RHEL support channels. What we will help you with here is the current utrace development code. Perhaps Oleg and/or I will get time soon to look into this issue. Chances are better if you provide a test case in the form of a simple utrace module and a test scenario using it. Thanks, Roland From dbaukus at conveycomputer.com Thu Nov 11 21:33:22 2010 From: dbaukus at conveycomputer.com (dave baukus) Date: Thu, 11 Nov 2010 15:33:22 -0600 Subject: Utrace .report_jctl serialization issue ? In-Reply-To: <20101111205351.6C09C400DB@magilla.sf.frob.com> References: <4CDC5441.6000209@conveycomputer.com> <20101111205351.6C09C400DB@magilla.sf.frob.com> Message-ID: <4CDC6122.3030809@conveycomputer.com> Roland McGrath wrote on 11/11/2010 02:53 PM: >> Is a utrace engine with .report_jctl enabled suppose to handle >> do_notify_parent_cldstop(current, notify) processing for the last >> stopping task ? Or should it muck with task->ptrace to force >> tracehook_notify_jctl() to return a non-zero value ? >> > I can't figure out exactly how to construe this as a question about the > utrace API. The documented API is that each thread gets a report_jctl > callback, and the @notify argument is zero in all threads but one. > > notify originates from do_signal_stop(); it is only non-zero when sig->group_stop_count is 1: notify = sig->group_stop_count == 1 ? CLD_STOPPED : 0; Herein lies the issue; becaues utrace_report_jctl() release the lock, sig->group_stop_count may be greater than 1 for all tasks as the execute the above line. >> I ask because I have a simple multi-threaded process with a utrace engine >> attached to the process group leader; .report_jctl is enabled. >> > Do you mean the thread_group leader of one process in the process group? > Or do you mean multiple utrace engines, one per thread, all in the process > whose pid==pgid (that's what "process group leader" means in POSIX)? > Sorry, old term from older RHEL task->group_leader; The first task; it does not really matter. > >> If I SIGTSTP the process, occasionally control is not returned to the >> shell. >> > That sounds like a kernel bug. There should be nothing your report_jctl > callback could do (assuming it doesn't send more signals itself) that > affects the normal job control semantics. > The bug comes about because utrace_report_jctl() releases the lock as detailed. > The kernels that are appropriate to discuss here are upstream kernels with > the current utrace patches applied (i.e. what you get in the current > utrace-ptrace git branch), or the most recent Fedora kernels that should > include that same code. The code in question might well be the same in > RHEL6 kernels, but RHEL issues need to be addressed through the proper RHEL > support channels. What we will help you with here is the current utrace > development code. > > Perhaps Oleg and/or I will get time soon to look into this issue. > Chances are better if you provide a test case in the form of a simple > utrace module and a test scenario using it. > > > Thanks, > Roland > > I apologize for posting to the wrong forum. If I get a chance I will post module and test case, but as you point out I am not on the correct code base for this forum. Thank you for your time. Dave From oleg at redhat.com Mon Nov 15 19:05:37 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Mon, 15 Nov 2010 20:05:37 +0100 Subject: gdbstub initial code, v16 Message-ID: <20101115190537.GA15725@redhat.com> The only change is hardware watchpoints. Well. I can't say this change is good. Because ugdb uses (unexported) arch_ptrace() to set debugregs in a very much x86-specific way. However, I do not see what else can I do. 2.6.32 doesn't have the generic hardware breakpoint handler interface. And I can't play with thread.debugregX by hand, otherwise ugdb can't be compiled with the fresh kernels. arch_ptrace() method should work (I hope) with any kernel. But, this obviously means more multitracing problems. Perhaps ugdb needs the "can_use_hw_watchpoints" parameter. Also, currently the usage of debugregs is far from optimal, hopefully it is simple to improve. And. I think it makes sense to change gdb somehow. Even if it works with gdbserver, it falls back to stepping if the size of wp is too big for hw (default_region_ok_for_hw_watchpoint). This means that ugdb can't be faster in this case although it obviously could. What should I do next? (apart from internal changes, of course) Say, should I implement vRun? From the very beginnig, I hate the idea to exec the target from kernel space, but otoh I'm afraid this is important for gdb users. Oleg. -------------- next part -------------- #include #include #include #include #include #include #include #include static int o_remote_debug; module_param_named(echo, o_remote_debug, bool, 0); #define BUFFER_SIZE 1152 #define PACKET_SIZE 1152 struct pbuf { char *cur, *pkt; char buf[BUFFER_SIZE]; }; static inline void pb_init(struct pbuf *pb) { pb->cur = pb->buf; pb->pkt = NULL; } enum { U_STOP_IDLE = 0, U_STOP_PENDING, U_STOP_SENT, }; #define u_after(a, b) ((long)(b) - (long)(a) < 0) struct ugdb { struct list_head u_processes; struct list_head u_stopped; int u_stop_state; struct mutex u_mutex; spinlock_t u_slock; struct ugdb_thread *u_cur_tinfo, *u_cur_hg, *u_cur_hc; unsigned long u_genctr; wait_queue_head_t u_wait; int u_err; struct pbuf u_pbuf; char u_cbuf[PACKET_SIZE]; int u_clen; sigset_t u_sig_ign; unsigned int u_no_ack:1, u_allstop:1; }; static inline void ugdb_ck_stopped(struct ugdb *ugdb) { spin_lock(&ugdb->u_slock); WARN_ON(!list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_IDLE); WARN_ON(list_empty(&ugdb->u_stopped) && ugdb->u_stop_state == U_STOP_PENDING); spin_unlock(&ugdb->u_slock); } static struct ugdb *ugdb_create(void) { struct ugdb *ugdb; int err; err = -ENODEV; // XXX: ugly. proc_reg_open() should take care. if (!try_module_get(THIS_MODULE)) goto out; err = -ENOMEM; ugdb = kzalloc(sizeof(*ugdb), GFP_KERNEL); if (!ugdb) goto put_module; INIT_LIST_HEAD(&ugdb->u_processes); INIT_LIST_HEAD(&ugdb->u_stopped); mutex_init(&ugdb->u_mutex); spin_lock_init(&ugdb->u_slock); init_waitqueue_head(&ugdb->u_wait); pb_init(&ugdb->u_pbuf); return ugdb; put_module: module_put(THIS_MODULE); out: return ERR_PTR(err); } struct x86_hw_wp { int nr; unsigned long dr[4]; unsigned long dr7; }; struct p_wp { struct rw_semaphore wp_sem; struct list_head wp_list; int wp_cnt, wp_mem; struct x86_hw_wp hw_wp; }; static inline void p_wp_init(struct p_wp *p_wp) { init_rwsem(&p_wp->wp_sem); INIT_LIST_HEAD(&p_wp->wp_list); } static void p_wp_free(struct p_wp *p_wp); #define P_DETACHING (1 << 1) #define P_ZOMBIE (1 << 2) struct ugdb_process { int p_pid; int p_state; struct p_wp p_wp; struct list_head p_threads; struct ugdb *p_ugdb; struct list_head p_processes; }; static inline bool process_alive(struct ugdb_process *process) { return !(process->p_state & P_ZOMBIE); } static inline void mark_process_dead(struct ugdb_process *process) { process->p_state |= P_ZOMBIE; } static struct ugdb_process *ugdb_create_process(struct ugdb *ugdb, int pid_nr) { struct ugdb_process *process; process = kzalloc(sizeof(*process), GFP_KERNEL); if (!process) return NULL; process->p_pid = pid_nr; process->p_ugdb = ugdb; INIT_LIST_HEAD(&process->p_threads); list_add_tail(&process->p_processes, &ugdb->u_processes); p_wp_init(&process->p_wp); return process; } #define T_STOP_RUN 0 #define T_STOP_REQ (1 << 0) /* requested by gdb */ #define T_STOP_ALL (1 << 1) /* vCont;c:pX.-1, for report_clone */ #define T_STOP_ACK (1 << 2) /* visible to vStopped */ #define T_STOP_STOPPED (1 << 3) /* reported as stopped to gdb */ /* TASK_TRACED + deactivated ? */ #define T_EV_NONE 0 #define T_EV_EXIT (1 << 24) #define T_EV_SIGN (2 << 24) #define T_EV_TYPE(event) ((0xff << 24) & (event)) #define T_EV_DATA(event) (~(0xff << 24) & (event)) #define HW_WP_NONE 0 #define HW_WP_ACTIVE 1 #define HW_WP_INVALID 2 struct t_wp { struct wp* wp_cur; int hw_wp_state; }; static inline void t_wp_init(struct ugdb_thread *thread) { } #define T_STEP_HARD 1 #define T_STEP_SOFT 2 struct ugdb_thread { int t_tid; int t_stop_state; int t_stop_event; int t_step; // XXX: move me into t_stop_event struct t_wp t_wp; siginfo_t *t_siginfo; struct ugdb *t_ugdb; struct ugdb_process *t_process; unsigned long t_genctr; struct list_head t_threads; struct list_head t_stopped; struct pid *t_spid; struct utrace_engine *t_engine; }; static inline bool thread_alive(struct ugdb_thread *thread) { WARN_ON((thread->t_tid != 0) != process_alive(thread->t_process)); return thread->t_tid != 0; } static inline void mark_thread_dead(struct ugdb_thread *thread) { mark_process_dead(thread->t_process); thread->t_tid = 0; } /* * The thread should be alive, and it can't pass ugdb_report_death() * if the caller holds ugdb->u_mutex. However the tracee can be * reaped anyway, pid_task() can return NULL after detach_pid(). */ static inline struct task_struct *thread_to_task(struct ugdb_thread *thread) { BUG_ON(!thread_alive(thread)); return pid_task(thread->t_spid, PIDTYPE_PID); } static struct ugdb_thread *ugdb_create_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; thread = kzalloc(sizeof(*thread), GFP_KERNEL); if (!thread) return NULL; thread->t_tid = pid_vnr(spid); thread->t_spid = get_pid(spid); thread->t_process = process; thread->t_ugdb = process->p_ugdb; thread->t_genctr = thread->t_ugdb->u_genctr; INIT_LIST_HEAD(&thread->t_stopped); list_add_tail(&thread->t_threads, &process->p_threads); t_wp_init(thread); return thread; } static void ugdb_del_stopped(struct ugdb *ugdb, struct ugdb_thread *thread) { if (!list_empty(&thread->t_stopped)) { WARN_ON(!(thread->t_stop_state & T_STOP_ACK)); spin_lock(&ugdb->u_slock); list_del_init(&thread->t_stopped); if (!(thread->t_stop_state & T_STOP_STOPPED)) { if (ugdb->u_stop_state == U_STOP_PENDING && list_empty(&ugdb->u_stopped)) ugdb->u_stop_state = U_STOP_IDLE; } spin_unlock(&ugdb->u_slock); } thread->t_stop_state = T_STOP_RUN; } static void ugdb_destroy_thread(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; ugdb_ck_stopped(ugdb); ugdb_del_stopped(ugdb, thread); /* NULL if attach fails */ if (thread->t_engine) utrace_engine_put(thread->t_engine); list_del(&thread->t_threads); put_pid(thread->t_spid); kfree(thread); } static int ugdb_set_events(struct ugdb_thread *thread, unsigned long events) { WARN_ON(!thread_alive(thread)); events |= (UTRACE_EVENT(CLONE) | UTRACE_EVENT(DEATH) | UTRACE_EVENT_SIGNAL_ALL); //XXX: I think utrace_get_signal() is buggy !!!!!!!!!!!! events |= UTRACE_EVENT(QUIESCE); return utrace_set_events_pid(thread->t_spid, thread->t_engine, events); } static int ugdb_control(struct ugdb_thread *thread, enum utrace_resume_action action) { // XXX: temporary racy check WARN_ON(!thread_alive(thread) && action != UTRACE_DETACH); return utrace_control_pid(thread->t_spid, thread->t_engine, action); } static const struct utrace_engine_ops ugdb_utrace_ops; static void ugdb_detach_thread(struct ugdb_thread *thread, bool running) { int ret; ret = ugdb_control(thread, UTRACE_DETACH); /* engine->flags == 0, it can't run a callback */ if (!running) return; /* callbacks are no longer possible */ if (!ret) return; if (ret == -EINPROGRESS) { /* * We raced with a callback, it can't be ->report_death(). * However, we can not use utrace_barrier_pid(), it can * hang "forever" until the next utrace_resume() if it * sees ->ops == &utrace_detached_ops set by us, but the * tracee is no longer running. * * But: we have no choice. */ do { ret = utrace_barrier_pid(thread->t_spid, thread->t_engine); } while (ret == -ERESTARTSYS); } else { /* * Nothing can help us to synchronize with ->report_death. * We do not know if it was already called or not, we can't * know if it is running. utrace_barrier_pid() can't help, * it can return zero and then later ->report_death() will * be called. Or it can return -ESRCH just because the task * was alredy released and pid_task() == NULL, but this * doesn't mean ->report_death() can't be called later. * * Fortunately, we know that the tracee is dying or dead, * engine->ops should be changed after ugdb_report_death() * returns UTRACE_DETACH. */ while (thread->t_engine->ops == &ugdb_utrace_ops) { schedule_timeout_uninterruptible(1); } } } /* * returns NULL if raced with exit(), or ERR_PTR(). */ static struct ugdb_thread *ugdb_attach_thread(struct ugdb_process *process, struct pid *spid) { struct ugdb_thread *thread; struct utrace_engine *engine; struct task_struct *task; thread = ugdb_create_thread(process, spid); if (!thread) goto err; engine = utrace_attach_pid(thread->t_spid, UTRACE_ATTACH_CREATE, &ugdb_utrace_ops, thread); if (IS_ERR(engine)) goto free_thread; thread->t_engine = engine; if (ugdb_set_events(thread, 0)) goto detach_thread; return thread; detach_thread: ugdb_detach_thread(thread, false); free_thread: ugdb_destroy_thread(thread); err: rcu_read_lock(); task = pid_task(spid, PIDTYPE_PID); if (task && task->exit_state) task = NULL; rcu_read_unlock(); return task ? ERR_PTR(-ENOMEM) : NULL; } static inline bool is_subthread(struct ugdb_process *process, struct ugdb_thread *thread) { return thread && thread->t_process == process; } static inline void ugdb_reset_tinfo(struct ugdb *ugdb) { ugdb->u_cur_tinfo = NULL; } static void ugdb_destroy_process(struct ugdb_process *process) { struct ugdb *ugdb = process->p_ugdb; struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); process->p_state |= P_DETACHING; list_del(&process->p_processes); if (is_subthread(process, ugdb->u_cur_hg)) ugdb->u_cur_hg = NULL; if (is_subthread(process, ugdb->u_cur_hc)) ugdb->u_cur_hc = NULL; /* I hope gdb won't do detach from under qfThreadInfo */ if (ugdb->u_cur_tinfo) { printk(KERN_WARNING "ugdb: detach from under qfThreadInfo\n"); ugdb_reset_tinfo(ugdb); } mutex_unlock(&ugdb->u_mutex); while (!list_empty(&process->p_threads)) { thread = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); ugdb_detach_thread(thread, true); ugdb_destroy_thread(thread); } BUG_ON(!list_empty(&process->p_threads)); p_wp_free(&process->p_wp); kfree(process); } static void ugdb_destroy(struct ugdb *ugdb) { struct ugdb_process *process; while (!list_empty(&ugdb->u_processes)) { process = list_first_entry(&ugdb->u_processes, struct ugdb_process, p_processes); ugdb_destroy_process(process); } BUG_ON(!list_empty(&ugdb->u_processes)); BUG_ON(!list_empty(&ugdb->u_stopped)); module_put(THIS_MODULE); kfree(ugdb); } static struct pid *get_next_pid(struct pid *main, struct pid *curr) { struct task_struct *task; struct sighand_struct *sighand; struct pid *next = NULL; rcu_read_lock(); /* * If task/sighand is NULL we return NULL. This is fine if * the caller is get_first_pid(), we should abort attaching. * * But this can also happen if curr was already attached, * and this is wrong. Fortunately, this is very unlikely * case. The attached sub-thread can't pass ->report_death, * if it was reaped the caller of release_task() must be * ptracer who re-parented this thread. */ task = pid_task(curr, PIDTYPE_PID); if (!task) goto unlock_rcu; // XXX: we need lock_task_sighand() but it is not exported, // so we ran race with de_thread(). sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); for (;;) { task = next_thread(task); // XXX: if main is not leader we can race with exec. if (task_pid(task) == main) break; if (!task->exit_state) { next = get_pid(task_pid(task)); break; } } spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); return next; } static struct pid *get_first_pid(struct pid *main) { struct task_struct *leader; rcu_read_lock(); leader = pid_task(main, PIDTYPE_PID); if (leader && leader->exit_state) leader = NULL; rcu_read_unlock(); /* * The group-leader is alive, try to attach. If it exits * before utrace_set_events(), get_first_pid() will be * called again and it will notice ->exit_state != 0. */ if (leader) return get_pid(main); /* * Try to find the live sub-thread. If the whole group * is dead it returns NULL and the caller aborts. */ return get_next_pid(main, main); } static int ugdb_attach_all_threads(struct ugdb *ugdb, struct ugdb_process *process, struct pid *main_pid) { struct ugdb_thread *thread; struct pid *curr_pid; mutex_lock(&ugdb->u_mutex); for (;;) { curr_pid = get_first_pid(main_pid); if (!curr_pid) goto abort; thread = ugdb_attach_thread(process, curr_pid); put_pid(curr_pid); if (IS_ERR(thread)) goto abort; if (thread) break; } for (;;) { struct pid *next_pid; next_pid = get_next_pid(main_pid, curr_pid); if (!next_pid) break; thread = ugdb_attach_thread(process, next_pid); put_pid(next_pid); if (IS_ERR(thread)) goto abort; if (!thread) continue; curr_pid = next_pid; } mutex_unlock(&ugdb->u_mutex); return 0; abort: mutex_unlock(&ugdb->u_mutex); return -1; } static int ugdb_attach(struct ugdb *ugdb, int pid_nr) { struct pid *main_pid; struct ugdb_process *process; int err; // XXX: check if exists // XXX: check if group leader ? err = -ESRCH; main_pid = find_get_pid(pid_nr); if (!main_pid) goto out; err = -ENOMEM; process = ugdb_create_process(ugdb, pid_nr); if (!process) goto free_pid; err = ugdb_attach_all_threads(ugdb, process, main_pid); if (err) ugdb_destroy_process(process); free_pid: put_pid(main_pid); out: return err; } static struct ugdb_process *ugdb_find_process(struct ugdb *ugdb, int pid) { struct ugdb_process *process; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (process->p_pid == pid) return process; } return NULL; } static struct ugdb_thread *ugdb_find_thread(struct ugdb *ugdb, int pid, int tid) { struct ugdb_process *process; struct ugdb_thread *thread; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (!tid || thread->t_tid == tid) return thread; } if (pid) break; } return NULL; } static int ugdb_detach(struct ugdb *ugdb, int pid) { struct ugdb_process *process = ugdb_find_process(ugdb, pid); if (!process) return -1; ugdb_destroy_process(process); return 0; } #define CUR_TINFO_END ((struct ugdb_thread *)1) static struct ugdb_thread *ugdb_advance_tinfo(struct ugdb *ugdb) { struct ugdb_thread *cur, *nxt; struct ugdb_process *process; cur = ugdb->u_cur_tinfo; if (cur == CUR_TINFO_END) { ugdb->u_cur_tinfo = NULL; return NULL; } if (!cur) { list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { cur = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } if (!cur) return NULL; } process = cur->t_process; if (list_is_last(&cur->t_threads, &process->p_threads)) { nxt = CUR_TINFO_END; list_for_each_entry_continue(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (!list_empty(&process->p_threads)) { nxt = list_first_entry(&process->p_threads, struct ugdb_thread, t_threads); break; } } } else { nxt = list_first_entry(&cur->t_threads, struct ugdb_thread, t_threads); } ugdb->u_cur_tinfo = nxt; return cur; } // ----------------------------------------------------------------------------- static bool ugdb_add_stopped(struct ugdb_thread *thread, int stop_event) { struct ugdb *ugdb = thread->t_ugdb; bool ret = false; ugdb_ck_stopped(ugdb); spin_lock(&ugdb->u_slock); if (stop_event == T_EV_NONE) { if (WARN_ON(thread->t_stop_state & T_STOP_ACK)) goto unlock; if (WARN_ON(!list_empty(&thread->t_stopped))) goto unlock; /* raced with ugdb_cont_thread() */ if (!(thread->t_stop_state & T_STOP_REQ)) goto unlock; } if (thread->t_stop_state & T_STOP_ACK) { if (thread->t_stop_state & T_STOP_STOPPED) /* * Alas, we can't report this event. We already * reported T00 and there is no way to inform gdb * the state of tracee was changed. */ goto unlock; } else { WARN_ON(thread->t_stop_state & T_STOP_STOPPED); thread->t_stop_state |= T_STOP_ACK; list_add_tail(&thread->t_stopped, &ugdb->u_stopped); if (ugdb->u_stop_state == U_STOP_IDLE) { ugdb->u_stop_state = U_STOP_PENDING; wake_up_all(&ugdb->u_wait); } } thread->t_stop_event = stop_event; ret = true; unlock: spin_unlock(&ugdb->u_slock); return ret; } static void ugdb_process_exit(struct ugdb_thread *thread) { struct ugdb *ugdb = thread->t_ugdb; int status; BUG_ON(!thread_alive(thread)); ugdb_del_stopped(ugdb, thread); mark_thread_dead(thread); // XXX: OOPS, we can't read ->signal->group_exit_code !!! status = current->exit_code; if (ugdb_add_stopped(thread, T_EV_EXIT | status)) return; WARN_ON(1); } static int ugdb_stop_thread(struct ugdb_thread *thread, bool all) { struct ugdb *ugdb = thread->t_ugdb; int err; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); if (thread->t_stop_state != T_STOP_RUN) { if (!all || (thread->t_stop_state & T_STOP_ALL)) return 0; /* * Otherwise we should set T_STOP_ALL anyway, * * (gdb) interrupt & * (gbd) interrupt -a & * * to ensure -a actually works if it races with clone. */ } err = -EALREADY; spin_lock(&ugdb->u_slock); if (thread->t_stop_state == T_STOP_RUN) { thread->t_stop_state = T_STOP_REQ; err = 0; } /* * We hold ugdb->u_mutex, we can't race with ugdb_report_clone(). * ugdb->u_slock protects us against ugdb_add_stopped(). We can * change ->t_stop_state even if we did not initiate this stop. */ if (all) thread->t_stop_state |= T_STOP_ALL; spin_unlock(&ugdb->u_slock); if (err) return 0; // XXX: we don't do UTRACE_STOP! this means we can't // stop TASK_STOPEED task. Need to discuss jctl issues. // if we do UTRACE_STOP we should call ugdb_add_stopped(). ugdb_set_events(thread, UTRACE_EVENT(QUIESCE)); err = ugdb_control(thread, UTRACE_INTERRUPT); if (err && err != -EINPROGRESS) return err; return 1; } static int ugdb_cont_thread(struct ugdb_thread *thread, bool all, int t_step) { struct ugdb *ugdb = thread->t_ugdb; int ret; WARN_ON(!thread_alive(thread)); ugdb_ck_stopped(ugdb); // XXX: gdb shouldn't explicitly cont an unreported thread WARN_ON(!all && !(thread->t_stop_state & T_STOP_STOPPED)); if (thread->t_stop_state == T_STOP_RUN) return 0; spin_lock(&ugdb->u_slock); /* * Nothing to do except clear the pending T_STOP_REQ. */ ret = 0; if (!(thread->t_stop_state & T_STOP_ACK)) goto set_run; /* * Alas. Thanks to remote protocol, we can't cont this * thread. We probably already sent the notification, we * can do nothing except ack that %Stop later in response * to vStopped. * * OTOH, gdb shouldn't send 'c' if this thread was not * reported as stopped. However, this means that gdb can * see the new %Stop:T00 notification after vCont;c:pX.-1, * it should handle this case correctly anyway. I hope. * * If this stop was not initiated by gdb we should not * cancel it too, this event should be reported first. */ ret = -1; if (!(thread->t_stop_state & T_STOP_STOPPED)) goto unlock; ret = 1; list_del_init(&thread->t_stopped); set_run: thread->t_stop_state = T_STOP_RUN; unlock: spin_unlock(&ugdb->u_slock); if (ret >= 0) { unsigned long events = 0; enum utrace_resume_action action = UTRACE_RESUME; thread->t_step = t_step; if (t_step) { /* to correctly step over syscall insn */ events |= UTRACE_EVENT(SYSCALL_EXIT); action = UTRACE_SINGLESTEP; } // XXX: OK, this all is racy, and I do not see any // solution except: implement UTRACE_STOP_STICKY and // move this code up under the lock, or add // utrace_engine_ops->notify_stopped(). // 1. UTRACE_RESUME is racy, this is fixeable. // 2. we need utrace_barrier() to close the race // with the callback which is going to return // UTRACE_STOP, but: // a) we can deadlock (solveable) // b) in this case UTRACE_RESUME can race with // another stop initiated by tracee itself. ugdb_set_events(thread, events); ugdb_control(thread, action); } return ret; } static struct ugdb_thread *ugdb_next_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread = NULL; // XXX: temporary racy check WARN_ON(ugdb->u_stop_state == U_STOP_IDLE); spin_lock(&ugdb->u_slock); if (list_empty(&ugdb->u_stopped)) { ugdb->u_stop_state = U_STOP_IDLE; } else { ugdb->u_stop_state = U_STOP_SENT; thread = list_first_entry(&ugdb->u_stopped, struct ugdb_thread, t_stopped); thread->t_stop_state |= T_STOP_STOPPED; list_del_init(&thread->t_stopped); } spin_unlock(&ugdb->u_slock); return thread; } // ----------------------------------------------------------------------------- static bool ugdb_stop_pending(struct ugdb_thread *thread) { if (!(thread->t_stop_state & T_STOP_REQ)) return false; if (!(thread->t_stop_state & T_STOP_ACK)) return ugdb_add_stopped(thread, T_EV_NONE); return true; } static u32 ugdb_report_quiesce(u32 action, struct utrace_engine *engine, unsigned long event) { struct ugdb_thread *thread = engine->data; WARN_ON(!thread_alive(thread)); /* ensure SIGKILL can't race with stop/cont in progress */ if (event != UTRACE_EVENT(DEATH)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP; } return utrace_resume_action(action); } static int cont_signal(struct ugdb_thread *thread, struct k_sigaction *return_ka) { int signr = T_EV_DATA(thread->t_stop_event); siginfo_t *info = thread->t_siginfo; thread->t_siginfo = NULL; if (WARN_ON(!valid_signal(signr))) return 0; if (!signr) return signr; /* * Update the siginfo structure if the signal has changed. */ if (info->si_signo != signr) { info->si_signo = signr; info->si_errno = 0; info->si_code = SI_USER; info->si_pid = 0; info->si_uid = 0; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, info, current); signr = 0; } else { spin_lock_irq(¤t->sighand->siglock); *return_ka = current->sighand->action[signr - 1]; spin_unlock_irq(¤t->sighand->siglock); } return signr; } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info); static u32 ugdb_report_signal(u32 action, struct utrace_engine *engine, struct pt_regs *regs, siginfo_t *info, const struct k_sigaction *orig_ka, struct k_sigaction *return_ka) { struct ugdb_thread *thread = engine->data; struct ugdb *ugdb = thread->t_ugdb; int signr; WARN_ON(!thread_alive(thread)); switch (utrace_signal_action(action)) { case UTRACE_SIGNAL_HANDLER: if (WARN_ON(thread->t_siginfo)) thread->t_siginfo = NULL; if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } /* Fall through */ default: if (orig_ka) break; /* * It was UTRACE_SIGNAL_REPORT, but another tracer has * changed utrace_report->result to deliver or stop. * Fall through. */ case UTRACE_SIGNAL_REPORT: if (!thread->t_siginfo) { /* UTRACE_INTERRUPT from ugdb_report_syscall_exit() */ if (thread->t_step) { WARN_ON(orig_ka); // user_single_step_siginfo(current, regs, info); memset(info, 0, sizeof(*info)); info->si_signo = SIGTRAP; break; } } else { if (WARN_ON(thread->t_siginfo != info)) return action; WARN_ON(T_EV_TYPE(thread->t_stop_event) != T_EV_SIGN); signr = cont_signal(thread, return_ka); if (signr) { /* * Consider: * * (gdb) signal SIG & * (gdb) interrupt * * We shouldn't miss the new stop request, so * we do not return from here. */ action = UTRACE_RESUME | UTRACE_SIGNAL_DELIVER; } } if (ugdb_stop_pending(thread)) return UTRACE_STOP | utrace_signal_action(action); if (thread->t_step) return UTRACE_SINGLESTEP | utrace_signal_action(action); return action; } WARN_ON(thread->t_siginfo); signr = info->si_signo; if (WARN_ON(!signr || !valid_signal(signr))) return action; if (wp_next_soft_trap(thread, info)) { if (ugdb_stop_pending(thread)) return UTRACE_STOP | UTRACE_SIGNAL_IGN; return UTRACE_SINGLESTEP | UTRACE_SIGNAL_IGN; } if (sigismember(&ugdb->u_sig_ign, signr)) return action; if (ugdb_add_stopped(thread, T_EV_SIGN | signr)) { thread->t_siginfo = info; /* * Make sure the subsequent UTRACE_SIGNAL_REPORT clears * ->t_siginfo before return from get_signal_to_deliver(). */ if (utrace_control(current, engine, UTRACE_INTERRUPT)) WARN_ON(1); return UTRACE_STOP | UTRACE_SIGNAL_IGN; } /* * We already reported T00 to gdb. We can't change our state, * we are already stopped from gdb pov. Push back this signal * to report it later, after "continue". * * Not multitrace-friendly. */ return UTRACE_STOP | UTRACE_SIGNAL_REPORT | UTRACE_SIGNAL_HOLD; } static u32 ugdb_report_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { struct ugdb_thread *thread = engine->data; if (thread->t_step) return UTRACE_INTERRUPT; printk(KERN_INFO "ugdb: unexpected SYSCALL_EXIT\n"); return action; } static bool is_already_attached(struct ugdb_process *process, struct task_struct *task) { struct ugdb_thread *thread; if (likely(!task_utrace_flags(task))) return false; /* * Currently there is no way to know if it was attached by us. * We can't trust utrace_attach_task(UTRACE_ATTACH_MATCH_OPS), * ugdb attaches without UTRACE_ATTACH_EXCLUSIVE. We have to * check every attached thread. * * This is really bad, but without multitracing this can only * happen in unlikely case right after ugdb_attach_all_threads(). */ list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_spid == task_pid(task)) return true; } return false; } static void ugdb_wp_clone(struct ugdb_thread *thread); static u32 ugdb_report_clone(u32 action, struct utrace_engine *engine, unsigned long clone_flags, struct task_struct *task) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; struct ugdb_thread *new_thread; WARN_ON(!thread_alive(thread)); if (!(clone_flags & CLONE_THREAD)) goto out; mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; /* * This can only happen if we raced with ugdb_attach() which * could attach both current and the new PF_STARTING child. */ if (unlikely(is_already_attached(process, task))) goto unlock; new_thread = ugdb_attach_thread(process, task_pid(task)); BUG_ON(!new_thread); if (WARN_ON(IS_ERR(new_thread))) goto unlock; if (thread->t_stop_state & T_STOP_ALL) ugdb_stop_thread(new_thread, false); else ugdb_wp_clone(new_thread); unlock: mutex_unlock(&ugdb->u_mutex); out: return utrace_resume_action(action); } static u32 ugdb_report_death(struct utrace_engine *engine, bool group_dead, int signal) { struct ugdb_thread *thread = engine->data; struct ugdb_process *process = thread->t_process; struct ugdb *ugdb = thread->t_ugdb; WARN_ON(!thread_alive(thread)); mutex_lock(&ugdb->u_mutex); if (process->p_state & P_DETACHING) goto unlock; if (ugdb->u_cur_hg == thread) ugdb->u_cur_hg = NULL; if (ugdb->u_cur_hc == thread) ugdb->u_cur_hc = NULL; if (ugdb->u_cur_tinfo == thread) ugdb_advance_tinfo(ugdb); if (list_is_singular(&process->p_threads)) ugdb_process_exit(thread); else ugdb_destroy_thread(thread); unlock: mutex_unlock(&ugdb->u_mutex); return UTRACE_DETACH; } static const struct utrace_engine_ops ugdb_utrace_ops = { .report_quiesce = ugdb_report_quiesce, .report_signal = ugdb_report_signal, .report_syscall_exit = ugdb_report_syscall_exit, .report_clone = ugdb_report_clone, .report_death = ugdb_report_death, }; // ----------------------------------------------------------------------------- static inline int pb_size(struct pbuf *pb) { return pb->cur - pb->buf; } static inline int pb_room(struct pbuf *pb) { return pb->buf + BUFFER_SIZE - pb->cur; } static inline void pb_putc(struct pbuf *pb, char c) { if (WARN_ON(pb->cur >= pb->buf + BUFFER_SIZE)) return; *pb->cur++ = c; } static void pb_memcpy(struct pbuf *pb, const void *data, int size) { if (WARN_ON(size > pb_room(pb))) return; memcpy(pb->cur, data, size); pb->cur += size; } static inline void pb_puts(struct pbuf *pb, const char *s) { pb_memcpy(pb, s, strlen(s)); } static inline void pb_putb(struct pbuf *pb, unsigned char val) { static char hex[] = "0123456789abcdef"; pb_putc(pb, hex[(val & 0xf0) >> 4]); pb_putc(pb, hex[(val & 0x0f) >> 0]); } static void pb_putbs(struct pbuf *pb, const char *data, int size) { while (size--) pb_putb(pb, *data++); } static inline void __pb_start(struct pbuf *pb, char pref) { WARN_ON(pb->pkt); pb_putc(pb, pref); pb->pkt = pb->cur; } static inline void pb_start(struct pbuf *pb) { return __pb_start(pb, '$'); } static inline void pb_cancel(struct pbuf *pb) { if (WARN_ON(!pb->pkt)) return; pb->cur = pb->pkt - 1; pb->pkt = NULL; } static void pb_end(struct pbuf *pb) { unsigned char csm = 0; char *pkt = pb->pkt; pb->pkt = NULL; if (WARN_ON(!pkt)) return; while (pkt < pb->cur) { /* pb_qfer() can write '%' */ WARN_ON(*pkt == '$' || *pkt == '#'); csm += (unsigned char)*pkt++; } pb_putc(pb, '#'); pb_putb(pb, csm); } static inline void pb_packs(struct pbuf *pb, const char *s) { pb_start(pb); pb_puts(pb, s); pb_end(pb); } static void __attribute__ ((format(printf, 3, 4))) __pb_format(struct pbuf *pb, bool whole_pkt, const char *fmt, ...) { int room = pb_room(pb), size; va_list args; if (whole_pkt) pb_start(pb); va_start(args, fmt); size = vsnprintf(pb->cur, room, fmt, args); va_end(args); if (WARN_ON(size > room)) return; pb->cur += size; if (whole_pkt) pb_end(pb); } #define pb_printf(pb, args...) __pb_format((pb), false, args) #define pb_packf(pb, args...) __pb_format((pb), true, args) static int pb_qfer(struct pbuf *pb, const void *_data, int len, bool more) { const unsigned char *data = _data; int i; if (pb_room(pb) < 3 + len * 2) { WARN_ON(1); return -EOVERFLOW; } pb_start(pb); pb_putc(pb, more ? 'm' : 'l'); for (i = 0; i < len; ++i) { unsigned char c = data[i]; if (c == '$' || c == '#' || c == '}' || c == '*') { pb_putc(pb, '}'); c ^= 0x20; } pb_putc(pb, c); } pb_end(pb); return 0; } // XXX: improve me! static inline int pb_max_bs_size(struct pbuf *pb) { int size = pb_room(pb) - 4; return size > 0 ? size / 2 : 0; } static inline void *pb_alloc_bs(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < 2 * size + 4)) return NULL; return pb->cur + size + 1; } static inline void *pb_alloc_tmp(struct pbuf *pb, int size) { if (unlikely(pb_room(pb) < size)) return NULL; return pb->cur + BUFFER_SIZE - size; } static inline void pb_flush(struct pbuf *pb, int size) { int keep = pb_size(pb) - size; if (keep) memmove(pb->buf, pb->buf + size, keep); pb->cur -= size; } static int pb_copy_to_user(struct pbuf *pb, char __user *ubuf, int size) { int copy = min(size, pb_size(pb)); if (!copy) return -EAGAIN; if (o_remote_debug) printk(KERN_INFO "<= %.*s\n", min(copy, 64), pb->buf); if (copy_to_user(ubuf, pb->buf, copy)) return -EFAULT; pb_flush(pb, copy); return copy; } // ----------------------------------------------------------------------------- static typeof(access_process_vm) *u_access_process_vm; static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam); static inline int ugdb_readmeam(struct ugdb *ugdb, unsigned long addr, int size, void *kbuf) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) return ret; ret = u_access_process_vm(task, addr, kbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; return ret; } #define WP_CHANGED 0 struct wp { unsigned long flags; struct list_head wp_node; unsigned long addr; int size; unsigned long data[0]; }; static void p_wp_free(struct p_wp *p_wp) { struct wp *wp, *n; list_for_each_entry_safe(wp, n, &p_wp->wp_list, wp_node) { p_wp->wp_cnt -= 1; p_wp->wp_mem -= wp->size; kfree(wp); } WARN_ON(p_wp->wp_cnt || p_wp->wp_mem); } static inline struct wp *wp_alloc(struct ugdb *ugdb, unsigned long addr, int size) { struct wp *wp; wp = kmalloc(sizeof(*wp) + size, GFP_KERNEL); if (!wp) return wp; wp->flags = 0; wp->addr = addr; wp->size = size; // XXX: and what should we do if it fails? ugdb_readmeam(ugdb, addr, size, wp->data); return wp; } static inline struct wp *wp_find(struct p_wp *p_wp, unsigned long addr, int size) { struct wp *wp; list_for_each_entry(wp, &p_wp->wp_list, wp_node) if (wp->addr == addr && wp->size == size) return wp; return NULL; } #define WP_MAX_CNT 64 #define WP_MAX_MEM 4096 #define WP_MAX_LEN 1024 // ----------------------------------------------------------------------------- #include #define X86_BREAKPOINT_LEN_1 0x40 #define X86_BREAKPOINT_LEN_2 0x44 #define X86_BREAKPOINT_LEN_4 0x4c #define X86_BREAKPOINT_LEN_8 0x48 #define X86_BREAKPOINT_WRITE 0x81 #define HBP_NUM 4 static inline unsigned long __encode_dr7(int drnum, unsigned int len, unsigned int type) { unsigned long bp_info; bp_info = (len | type) & 0xf; bp_info <<= (DR_CONTROL_SHIFT + drnum * DR_CONTROL_SIZE); bp_info |= (DR_GLOBAL_ENABLE << (drnum * DR_ENABLE_SIZE)); return bp_info; } static inline bool x86_hw_wp_active(struct x86_hw_wp *hw_wp) { return hw_wp->nr; } static int x86_build_hw_wp(struct p_wp *p_wp, struct x86_hw_wp *hw_wp) { struct wp *wp; unsigned long dr7 = 0; unsigned int nr = 0; hw_wp->nr = 0; hw_wp->dr7 = 0; list_for_each_entry(wp, &p_wp->wp_list, wp_node) { u8 hw_len; if (nr >= HBP_NUM) return -EINVAL; switch (wp->size) { default: return -EINVAL; case 1: hw_len = X86_BREAKPOINT_LEN_1; break; case 2: hw_len = X86_BREAKPOINT_LEN_2; break; case 4: hw_len = X86_BREAKPOINT_LEN_4; break; case 8: hw_len = X86_BREAKPOINT_LEN_8; break; } if (wp->addr & (wp->size - 1)) return -EINVAL; // XXX: TIF_IA32? IA32_PAGE_OFFSET? if (wp->addr >= TASK_SIZE - 8) return -EINVAL; hw_wp->dr[nr] = wp->addr; dr7 |= __encode_dr7(nr, hw_len, X86_BREAKPOINT_WRITE); nr++; } hw_wp->nr = nr; hw_wp->dr7 = dr7; return 0; } static void x86_update_hw_wp(struct ugdb *ugdb, struct ugdb_process *process) { bool old_active, new_active; struct p_wp *p_wp = &process->p_wp; struct x86_hw_wp hw_wp; x86_build_hw_wp(p_wp, &hw_wp); old_active = x86_hw_wp_active(&p_wp->hw_wp); new_active = x86_hw_wp_active(&hw_wp); if (!old_active && !new_active) return; mutex_lock(&ugdb->u_mutex); p_wp->hw_wp = hw_wp; if (old_active) { struct ugdb_thread *thread; list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_wp.hw_wp_state == HW_WP_ACTIVE) thread->t_wp.hw_wp_state = HW_WP_INVALID; } } mutex_unlock(&ugdb->u_mutex); } #include static typeof(arch_ptrace) *u_arch_ptrace; static int x86_set_dr(struct task_struct *task, int drnum, unsigned long val) { int ret = u_arch_ptrace(task, PTRACE_POKEUSR, offsetof(struct user, u_debugreg[drnum]), val); if (ret) printk(KERN_INFO "ugdb: set_dr(%d, %d, %lx) failed: %d\n", task->pid, drnum, val, ret); return ret; } static void x86_apply_hw_bp(struct ugdb_thread *thread) { struct x86_hw_wp *hw_wp = &thread->t_process->p_wp.hw_wp; struct task_struct *task = thread_to_task(thread); int state = HW_WP_INVALID; int nr; if (!task) goto err; for (nr = 0; nr < hw_wp->nr; ++nr) { if (x86_set_dr(task, nr, hw_wp->dr[nr])) goto err; } if (x86_set_dr(task, 7, hw_wp->dr7)) goto err; state = x86_hw_wp_active(hw_wp) ? HW_WP_ACTIVE : HW_WP_NONE; err: thread->t_wp.hw_wp_state = state; } static inline bool need_sync_hw_wp(struct ugdb_thread *thread) { int state = thread->t_wp.hw_wp_state; bool active; if (state == HW_WP_INVALID) return true; active = x86_hw_wp_active(&thread->t_process->p_wp.hw_wp); if (active != (state == HW_WP_ACTIVE)) return true; return false; } static void thread_sync_hw_wp(struct ugdb_thread *thread) { if (!need_sync_hw_wp(thread)) return; x86_apply_hw_bp(thread); } static bool has_watchpoints(struct ugdb_thread *thread) { return unlikely(!list_empty(&thread->t_process->p_wp.wp_list)); } static inline bool has_soft_watchpoints(struct ugdb_thread *thread) { return has_watchpoints(thread) && thread->t_wp.hw_wp_state != HW_WP_ACTIVE; } // ----------------------------------------------------------------------------- static const char *handle_z(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; bool insert; int type; struct ugdb_process *process; struct p_wp *p_wp; struct wp *wp; insert = (*cmd++ == 'Z'); if (sscanf(cmd, "%d,%lx,%lx", &type, &addr, &size) != 3) return "E01"; if (type != 2) return ""; if (size > WP_MAX_LEN) return "E01"; process = NULL; mutex_lock(&ugdb->u_mutex); if (ugdb->u_cur_hg) process = ugdb->u_cur_hg->t_process; mutex_unlock(&ugdb->u_mutex); if (!process) return "E01"; p_wp = &process->p_wp; wp = wp_find(p_wp, addr, size); if (insert) { if (wp) return "E01"; if (!size || size > WP_MAX_LEN || p_wp->wp_cnt + 1 > WP_MAX_CNT || p_wp->wp_mem + size > WP_MAX_MEM) return "E01"; wp = wp_alloc(ugdb, addr, size); if (!wp) return "E01"; down_write(&p_wp->wp_sem); list_add_tail(&wp->wp_node, &p_wp->wp_list); up_write(&p_wp->wp_sem); p_wp->wp_cnt += 1; p_wp->wp_mem += size; } else { if (!wp) return "E01"; down_write(&p_wp->wp_sem); list_del(&wp->wp_node); up_write(&p_wp->wp_sem); if (test_bit(WP_CHANGED, &wp->flags)) { struct ugdb_thread *thread; mutex_lock(&ugdb->u_mutex); list_for_each_entry(thread, &process->p_threads, t_threads) { if (thread->t_wp.wp_cur == wp) thread->t_wp.wp_cur = NULL; } mutex_unlock(&ugdb->u_mutex); } p_wp->wp_cnt -= 1; p_wp->wp_mem -= size; kfree(wp); } x86_update_hw_wp(ugdb, process); return "OK"; } #define WP_NO_WATCH -1ul static unsigned long get_cur_watch(struct ugdb_thread *thread) { struct wp *wp = thread->t_wp.wp_cur; if (likely(!wp)) return WP_NO_WATCH; thread->t_wp.wp_cur = NULL; clear_bit(WP_CHANGED, &wp->flags); return wp->addr; } static int memcmp_user(void *kp, void __user *up, int sz) { unsigned char data[64]; while (sz) { int size = sizeof(data); if (size > sz) size = sz; if (copy_from_user(data, up, size)) ; if (memcmp(data, kp, size)) return 1; up += size; kp += size; sz -= size; } return 0; } static bool check_one_wp(struct wp *wp) { void __user *up = (void __user*)wp->addr; if (test_bit(WP_CHANGED, &wp->flags)) return false; if (!memcmp_user(wp->data, up, wp->size)) return false; if (test_and_set_bit(WP_CHANGED, &wp->flags)) return false; copy_from_user(wp->data, up, wp->size); return true; } static bool check_watchpoints(struct ugdb_thread *thread) { struct p_wp *p_wp = &thread->t_process->p_wp; struct wp *wp; bool ret = false; down_read(&p_wp->wp_sem); list_for_each_entry(wp, &p_wp->wp_list, wp_node) { ret = check_one_wp(wp); if (ret) { thread->t_wp.wp_cur = wp; break; } } up_read(&p_wp->wp_sem); return ret; } static bool wp_next_soft_trap(struct ugdb_thread *thread, siginfo_t *info) { if (!has_watchpoints(thread)) return false; if (check_watchpoints(thread)) return false; return info->si_signo == SIGTRAP && thread->t_step == T_STEP_SOFT && // XXX: this filters out do_int3() only. // XXX: this is not right, we probably need // to check trap_no == 1, but then we need // unexported user_single_step_siginfo() for // ugdb_report_signal(). current->thread.trap_no != 3; } static void ugdb_wp_clone(struct ugdb_thread *thread) { if (!has_watchpoints(thread)) return; thread_sync_hw_wp(thread); if (has_soft_watchpoints(thread)) { thread->t_step = T_STEP_SOFT; ugdb_set_events(thread, UTRACE_EVENT(SYSCALL_EXIT)); ugdb_control(thread, UTRACE_SINGLESTEP); } } // ----------------------------------------------------------------------------- // XXX: include/gdb/signals.h:target_signal // incomplete: 7, 29, rt? static int to_gdb_sigmap[] = { [SIGHUP] = 1, [SIGINT] = 2, [SIGQUIT] = 3, [SIGILL] = 4, [SIGTRAP] = 5, [SIGABRT] = 6, [SIGIOT] = 0, /* ??? */ [SIGBUS] = 10, [SIGFPE] = 8, [SIGKILL] = 9, [SIGUSR1] = 30, [SIGSEGV] = 11, [SIGUSR2] = 31, [SIGPIPE] = 13, [SIGALRM] = 14, [SIGTERM] = 15, [SIGSTKFLT] = 0, /* ??? */ [SIGCHLD] = 20, [SIGCONT] = 19, [SIGSTOP] = 17, [SIGTSTP] = 18, [SIGTTIN] = 21, [SIGTTOU] = 22, [SIGURG] = 16, [SIGXCPU] = 24, [SIGXFSZ] = 25, [SIGVTALRM] = 26, [SIGPROF] = 27, [SIGWINCH] = 28, [SIGIO] = 23, [SIGPWR] = 32, [SIGSYS] = 12, }; static int sig_to_gdb(unsigned sig) { if (sig < ARRAY_SIZE(to_gdb_sigmap) && to_gdb_sigmap[sig]) return to_gdb_sigmap[sig]; return sig; } static int sig_from_gdb(unsigned sig) { int i; // XXX: valid_signal() is wrong, gdb has its own idea // about signals. fix to_gdb_sigmap[]. if (!sig || !valid_signal(sig)) return 0; for (i = 0; i < ARRAY_SIZE(to_gdb_sigmap); i++) { if (to_gdb_sigmap[i] == sig) return i; } return sig; } static int ugdb_report_stopped(struct ugdb *ugdb, bool async) { struct ugdb_thread *thread; int pid, tid, event, data; unsigned long watch; struct pbuf *pb; char ex_r; mutex_lock(&ugdb->u_mutex); thread = ugdb_next_stopped(ugdb); if (!thread) goto unlock; event = thread->t_stop_event; watch = get_cur_watch(thread); WARN_ON(thread_alive(thread) != (T_EV_TYPE(event) != T_EV_EXIT)); pid = thread->t_process->p_pid; tid = thread->t_tid; unlock: mutex_unlock(&ugdb->u_mutex); if (!thread) return false; pb = &ugdb->u_pbuf; // XXX: damn, cleanup me... if (async) { __pb_start(pb, '%'); pb_puts(pb, "Stop:"); } else { pb_start(pb); } data = T_EV_DATA(event); switch (T_EV_TYPE(event)) { case T_EV_EXIT: if (data & 0xff) { data = sig_to_gdb(data & 0xff); ex_r = 'X'; } else { data >>= 8; ex_r = 'W'; } pb_printf(pb, "%c%x;process:%x", ex_r, data, pid); ugdb_destroy_process(thread->t_process); break; case T_EV_SIGN: case T_EV_NONE: pb_printf(pb, "T%02xthread:p%x.%x;", sig_to_gdb(data), pid, tid); if (unlikely(watch != WP_NO_WATCH)) pb_printf(pb, "watch:%lx;", watch); break; default: printk(KERN_INFO "ugdb: bad stop event %x\n", event); } pb_end(pb); return true; } const char *handle_vstopped(struct ugdb *ugdb) { if (ugdb->u_stop_state != U_STOP_SENT) return "E01"; if (ugdb_report_stopped(ugdb, false)) return NULL; return "OK"; } static const char *handle_thread_info(struct ugdb *ugdb, bool start) { struct ugdb_thread *thread; int pid = 0, tid; mutex_lock(&ugdb->u_mutex); if (start) ugdb_reset_tinfo(ugdb); else if (!ugdb->u_cur_tinfo) printk(KERN_INFO "ugdb: unexpected qsThreadInfo\n"); thread = ugdb_advance_tinfo(ugdb); if (thread) { pid = thread->t_process->p_pid; tid = thread->t_tid; } mutex_unlock(&ugdb->u_mutex); if (!pid) return start ? "E01" : "l"; pb_packf(&ugdb->u_pbuf, "mp%x.%x", pid, tid); return NULL; } static char *parse_xid(char *str, int *ppid, bool multi) { if (*str == '-') { str++; if (multi && *str++ == '1') *ppid = -1; else str = NULL; } else { char *cur = str; *ppid = simple_strtoul(cur, &str, 16); if (str == cur) str = NULL; } return str; } static char *parse_pid_tid(char *str, int *ppid, int *ptid, bool multi) { if (*str++ != 'p') return NULL; str = parse_xid(str, ppid, multi); if (!str) return NULL; if (*str++ != '.') return NULL; str = parse_xid(str, ptid, multi); if (!str) return NULL; return str; } static const char *handle_set_cur(struct ugdb *ugdb, char *cmd) { struct ugdb_thread **pthread; int pid, tid; switch (*cmd++) { case 'g': pthread = &ugdb->u_cur_hg; break; case 'c': pthread = &ugdb->u_cur_hc; break; default: goto err; } if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); *pthread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (*pthread) return "OK"; err: return "E01"; } static const char *handle_ck_alive(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; int pid = 0, tid; if (!parse_pid_tid(cmd, &pid, &tid, false)) goto err; mutex_lock(&ugdb->u_mutex); thread = ugdb_find_thread(ugdb, pid, tid); mutex_unlock(&ugdb->u_mutex); if (thread) return "OK"; err: return "E01"; } static int parse_pid(char *str) { int pid; if (!parse_xid(str, &pid, false)) return 0; return pid; } static const char *handle_vattach(struct ugdb *ugdb, char *cmd) { int pid = parse_pid(cmd); if (pid && !ugdb_attach(ugdb, pid)) return "OK"; return "E01"; } static const char *handle_detach(struct ugdb *ugdb, char *cmd) { int pid; if (*cmd++ != ';') goto err; pid = parse_pid(cmd); if (pid && !ugdb_detach(ugdb, pid)) return "OK"; err: return "E01"; } typedef int (*each_func_t)(struct ugdb_thread *, void *); static int ugdb_do_each_thread(struct ugdb *ugdb, int pid, int tid, each_func_t func, void *arg) { struct ugdb_process *process; struct ugdb_thread *thread; int ret = -ESRCH; list_for_each_entry(process, &ugdb->u_processes, p_processes) { if (unlikely(!process_alive(process))) continue; if (pid > 0 && process->p_pid != pid) continue; list_for_each_entry(thread, &process->p_threads, t_threads) { if (WARN_ON(!thread_alive(thread))) continue; if (tid > 0 && thread->t_tid != tid) continue; ret = func(thread, arg); if (ret) goto out; if (tid >= 0) break; } if (pid >= 0) break; } out: return ret; } static int thread_cont_signal(struct ugdb_thread *thread, int signr) { /* * T_STOP_STOPPED was set under ->u_slock so we can't race * with ugdb_add_stopped() and get the wrong t_stop_event. * And, the tracee never changes it after T_STOP_STOPPED. */ switch (T_EV_TYPE(thread->t_stop_event)) { case T_EV_SIGN: WARN_ON(!T_EV_DATA(thread->t_stop_event)); thread->t_stop_event = T_EV_SIGN | signr; break; default: if (!signr) break; // XXX: temporary hack, will be reported. // but perhaps this is what we want ??? kill_pid(thread->t_spid, signr, 0); break; } return 0; } static int ugdb_resume_thread(struct ugdb_thread *thread, int signr, bool step, bool all) { int t_step; int ret = 0; /* * Otherwise I do not know what to do if sig/step, and anyway * I don't think gdb can try to cont a thread which was not * reported as stopped. */ if (!(thread->t_stop_state & T_STOP_STOPPED)) return ret; ret = thread_cont_signal(thread, signr); if (ret < 0) return ret; thread_sync_hw_wp(thread); t_step = 0; if (step) t_step = T_STEP_HARD; else if (has_soft_watchpoints(thread)) t_step = T_STEP_SOFT; return ugdb_cont_thread(thread, all, t_step); } static const char *handle_c(struct ugdb *ugdb, char *cmd) { struct ugdb_thread *thread; const char *rc = "E01"; int gdbsig, signr = 0; bool step; step = (*cmd == 'S' || *cmd == 's'); switch (*cmd++) { case 'C': case 'S': gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) return rc; signr = sig_from_gdb(gdbsig); if (!signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); if (*cmd == ';') ++cmd; /* fall */ case 'c': case 's': if (!*cmd) break; printk(KERN_INFO "ugdb: $c ADDR not implemented\n"); return rc; break; } mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hc; if (!thread) goto unlock; if (ugdb_resume_thread(thread, signr, step, false) <= 0) goto unlock; /* Suprise: non-stop should not reply! */ rc = NULL; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } struct vcont_arg { int pid, tid; bool intr; int signr; bool step; }; static char* parse_vcont_arg(char *cmd, struct vcont_arg *vcont) { vcont->intr = false; vcont->signr = 0; switch (*cmd++) { case 't': vcont->intr = true; break; case 'S': vcont->signr = 1; case 's': vcont->step = true; break; case 'C': vcont->signr = 1; case 'c': vcont->step = false; break; default: goto err; } if (vcont->signr) { int gdbsig = simple_strtoul(cmd, &cmd, 16); if (!gdbsig) goto err; vcont->signr = sig_from_gdb(gdbsig); if (!vcont->signr) printk(KERN_INFO "ugdb: sorry, can't map signal %d\n", gdbsig); } vcont->pid = -1; vcont->tid = -1; if (*cmd == ':') { cmd = parse_pid_tid(cmd + 1, &vcont->pid, &vcont->tid, true); if (!cmd) goto err; } return cmd; err: return NULL; } static int do_vcont_thread(struct ugdb_thread *thread, void *arg) { struct vcont_arg *vcont = arg; unsigned long genctr; bool all; int err; genctr = thread->t_ugdb->u_genctr; if (genctr == thread->t_genctr) return 0; WARN_ON_ONCE(u_after(thread->t_genctr, genctr)); thread->t_genctr = genctr; all = (vcont->tid < 0); if (vcont->intr) err = ugdb_stop_thread(thread, all); else err = ugdb_resume_thread(thread, vcont->signr, vcont->step, all); if (err < 0) return err; return 0; } static const char *handle_vcont(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; switch (*cmd) { case ';': break; case '?': return "vCont;t;c;C;s;S"; default: return "E01"; } mutex_lock(&ugdb->u_mutex); ugdb->u_genctr++; while (*cmd) { struct vcont_arg vcont_arg; int err; if (*cmd++ != ';') goto unlock; cmd = parse_vcont_arg(cmd, &vcont_arg); if (!cmd) goto unlock; err = ugdb_do_each_thread(ugdb, vcont_arg.pid, vcont_arg.tid, do_vcont_thread, &vcont_arg); if (err) goto unlock; } rc = "OK"; unlock: mutex_unlock(&ugdb->u_mutex); return rc; } static const char *handle_qpass_signals(struct ugdb *ugdb, char *cmd) { sigset_t *set = &ugdb->u_sig_ign; sigemptyset(set); while (*cmd) { char *end; int sig = simple_strtoul(cmd, &end, 16); if (cmd == end || *end != ';') return "E01"; cmd = end + 1; sig = sig_from_gdb(sig); if (!sig) // XXX: to_gdb_sigmap[] incomplete... // return "E01"; continue; sigaddset(set, sig); } return "OK"; } // ----------------------------------------------------------------------------- static struct task_struct * ugdb_prepare_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { struct ugdb_thread *thread; struct task_struct *task; int err; mutex_lock(&ugdb->u_mutex); thread = ugdb->u_cur_hg; if (!thread || !(thread->t_stop_state & T_STOP_STOPPED)) goto err; // XXX: u_cur_hg can't exit, we hold the mutex task = thread_to_task(thread); if (!task) goto err; for (;;) { if (fatal_signal_pending(current)) goto err; err = utrace_prepare_examine(task, thread->t_engine, exam); if (!err) break; if (err == -ESRCH) goto err; schedule_timeout_interruptible(1); } return task; err: mutex_unlock(&ugdb->u_mutex); return NULL; } // XXX: we hold the mutex in between, but only because we can't // use get_task_struct/put_task_struct. static int ugdb_finish_examine(struct ugdb *ugdb, struct utrace_examiner *exam) { // XXX: u_cur_hg can't exit, we hold the mutex struct ugdb_thread *thread = ugdb->u_cur_hg; struct task_struct *task = thread_to_task(thread); int ret = -ESRCH; if (task) ret = utrace_finish_examine(task, thread->t_engine, exam); mutex_unlock(&ugdb->u_mutex); return ret; } #define REGSET_GENERAL 0 #define REGSET_FP 1 #define MAX_REG_SIZE 16 struct gdbreg { unsigned short gdb_size, gdb_offs, rs_setno, usr_offs; }; // gdb/gdbserver/i387-fp.c:i387_fxsave struct gdb_i387_fxsave { unsigned short fctrl; unsigned short fstat; unsigned short ftag; unsigned short fop; unsigned int fioff; unsigned short fiseg; unsigned short pad1; unsigned int fooff; unsigned short foseg; unsigned short pad12; unsigned int mxcsr; unsigned int pad3; unsigned char st_space[128]; unsigned char xmm_space[256]; }; #define FPU__(mem) \ .rs_setno = REGSET_FP, \ .usr_offs = offsetof(struct gdb_i387_fxsave, mem) #define GEN__(mem) \ .rs_setno = REGSET_GENERAL, \ .usr_offs = offsetof(struct user_regs_struct, mem) /* generated from gdb/regformats/reg-x86-64-linux.dat */ struct gdbreg gdb_regmap_64[] = { [ 0] = { .gdb_size = 8, .gdb_offs = 0, GEN__(ax) }, [ 1] = { .gdb_size = 8, .gdb_offs = 8, GEN__(bx) }, [ 2] = { .gdb_size = 8, .gdb_offs = 16, GEN__(cx) }, [ 3] = { .gdb_size = 8, .gdb_offs = 24, GEN__(dx) }, [ 4] = { .gdb_size = 8, .gdb_offs = 32, GEN__(si) }, [ 5] = { .gdb_size = 8, .gdb_offs = 40, GEN__(di) }, [ 6] = { .gdb_size = 8, .gdb_offs = 48, GEN__(bp) }, [ 7] = { .gdb_size = 8, .gdb_offs = 56, GEN__(sp) }, [ 8] = { .gdb_size = 8, .gdb_offs = 64, GEN__(r8) }, [ 9] = { .gdb_size = 8, .gdb_offs = 72, GEN__(r9) }, [10] = { .gdb_size = 8, .gdb_offs = 80, GEN__(r10) }, [11] = { .gdb_size = 8, .gdb_offs = 88, GEN__(r11) }, [12] = { .gdb_size = 8, .gdb_offs = 96, GEN__(r12) }, [13] = { .gdb_size = 8, .gdb_offs = 104, GEN__(r13) }, [14] = { .gdb_size = 8, .gdb_offs = 112, GEN__(r14) }, [15] = { .gdb_size = 8, .gdb_offs = 120, GEN__(r15) }, [16] = { .gdb_size = 8, .gdb_offs = 128, GEN__(ip) }, [17] = { .gdb_size = 4, .gdb_offs = 136, GEN__(flags) }, [18] = { .gdb_size = 4, .gdb_offs = 140, GEN__(cs) }, [19] = { .gdb_size = 4, .gdb_offs = 144, GEN__(ss) }, [20] = { .gdb_size = 4, .gdb_offs = 148, GEN__(ds) }, [21] = { .gdb_size = 4, .gdb_offs = 152, GEN__(es) }, [22] = { .gdb_size = 4, .gdb_offs = 156, GEN__(fs) }, [23] = { .gdb_size = 4, .gdb_offs = 160, GEN__(gs) }, [24] = { .gdb_size = 10, .gdb_offs = 164, FPU__(st_space[0]) }, [25] = { .gdb_size = 10, .gdb_offs = 174, FPU__(st_space[16]) }, [26] = { .gdb_size = 10, .gdb_offs = 184, FPU__(st_space[32]) }, [27] = { .gdb_size = 10, .gdb_offs = 194, FPU__(st_space[48]) }, [28] = { .gdb_size = 10, .gdb_offs = 204, FPU__(st_space[64]) }, [29] = { .gdb_size = 10, .gdb_offs = 214, FPU__(st_space[80]) }, [30] = { .gdb_size = 10, .gdb_offs = 224, FPU__(st_space[96]) }, [31] = { .gdb_size = 10, .gdb_offs = 234, FPU__(st_space[112]) }, [32] = { .gdb_size = 4, .gdb_offs = 244, FPU__(fctrl) }, [33] = { .gdb_size = 4, .gdb_offs = 248, FPU__(fstat) }, [34] = { .gdb_size = 4, .gdb_offs = 252, FPU__(ftag) }, [35] = { .gdb_size = 4, .gdb_offs = 256, FPU__(fiseg) }, [36] = { .gdb_size = 4, .gdb_offs = 260, FPU__(fioff) }, [37] = { .gdb_size = 4, .gdb_offs = 264, FPU__(foseg) }, [38] = { .gdb_size = 4, .gdb_offs = 268, FPU__(fooff) }, [39] = { .gdb_size = 4, .gdb_offs = 272, FPU__(fop) }, [40] = { .gdb_size = 16, .gdb_offs = 276, FPU__(xmm_space[0]) }, [41] = { .gdb_size = 16, .gdb_offs = 292, FPU__(xmm_space[16]) }, [42] = { .gdb_size = 16, .gdb_offs = 308, FPU__(xmm_space[32]) }, [43] = { .gdb_size = 16, .gdb_offs = 324, FPU__(xmm_space[48]) }, [44] = { .gdb_size = 16, .gdb_offs = 340, FPU__(xmm_space[64]) }, [45] = { .gdb_size = 16, .gdb_offs = 356, FPU__(xmm_space[80]) }, [46] = { .gdb_size = 16, .gdb_offs = 372, FPU__(xmm_space[96]) }, [47] = { .gdb_size = 16, .gdb_offs = 388, FPU__(xmm_space[112]) }, [48] = { .gdb_size = 16, .gdb_offs = 404, FPU__(xmm_space[128]) }, [49] = { .gdb_size = 16, .gdb_offs = 420, FPU__(xmm_space[144]) }, [50] = { .gdb_size = 16, .gdb_offs = 436, FPU__(xmm_space[160]) }, [51] = { .gdb_size = 16, .gdb_offs = 452, FPU__(xmm_space[176]) }, [52] = { .gdb_size = 16, .gdb_offs = 468, FPU__(xmm_space[192]) }, [53] = { .gdb_size = 16, .gdb_offs = 484, FPU__(xmm_space[208]) }, [54] = { .gdb_size = 16, .gdb_offs = 500, FPU__(xmm_space[224]) }, [55] = { .gdb_size = 16, .gdb_offs = 516, FPU__(xmm_space[240]) }, [56] = { .gdb_size = 4, .gdb_offs = 532, FPU__(mxcsr) }, [57] = { .gdb_size = 8, .gdb_offs = 536, GEN__(orig_ax) }, }; #undef FPU__ #undef GEN__ static inline int rw_one_reg(struct task_struct *task, int regnum, unsigned char regval[], bool write) { const struct user_regset_view *view; const struct user_regset *rset; struct gdbreg *gdbreg; int err, count; view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: if (regnum >= ARRAY_SIZE(gdb_regmap_64)) return -EINVAL; gdbreg = gdb_regmap_64; count = sizeof(long); break; default: return -EIO; } gdbreg += regnum; rset = view->regsets + gdbreg->rs_setno; if (gdbreg->rs_setno != REGSET_GENERAL) count = gdbreg->gdb_size; if (WARN_ON(count > MAX_REG_SIZE)) return -EOVERFLOW; if (write) err = rset->set(task, rset, gdbreg->usr_offs, count, regval, NULL); else err = rset->get(task, rset, gdbreg->usr_offs, count, regval, NULL); return err ?: gdbreg->gdb_size; } static int ugdb_rw_one_reg(struct ugdb *ugdb, int regnum, unsigned char regval[], bool write) { struct utrace_examiner exam; struct task_struct *task; int ret = -ESRCH; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto ret; ret = rw_one_reg(task, regnum, regval, write); if (ugdb_finish_examine(ugdb, &exam)) ret = -ESRCH; ret: return ret; } // XXX: hex_to_bin() after 90378889 commit #include static int cap_hex_to_bin(char ch) { if ((ch >= '0') && (ch <= '9')) return ch - '0'; ch = tolower(ch); if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; return -1; } static int unhex(char *cmd, int size) { char *bytes = cmd; while (size--) { int lo, hi; hi = cap_hex_to_bin(*cmd++); lo = cap_hex_to_bin(*cmd++); if (lo < 0 || hi < 0) return -EINVAL; *bytes++ = (hi << 4) | lo; } return 0; } static const char *handle_set_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned int reg; int skip; if (sscanf(cmd, "P%x=%n", ®, &skip) != 1) goto err; cmd += skip; len -= skip; if (len & 1) goto err; len /= 2; if (unhex(cmd, len)) goto err; if (ugdb_rw_one_reg(ugdb, reg, cmd, true) != len) goto err; return "OK"; err: return "E01"; } static const char *handle_get_reg(struct ugdb *ugdb, char *cmd, int len) { unsigned char regval[MAX_REG_SIZE]; unsigned int reg; int skip, size; if (sscanf(cmd, "p%x%n", ®, &skip) != 1) goto err; if (len != skip) goto err; size = ugdb_rw_one_reg(ugdb, reg, regval, false); if (size < 0) goto err; pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regval, size); pb_end(&ugdb->u_pbuf); return NULL; err: return "E01"; } static int rw_one_regset(struct task_struct *task, int rsn, const struct user_regset_view *view, void *reg_mem, int reg_size, struct gdbreg *reg_map, int reg_cnt, void *gdb_mem, bool write) { const struct user_regset *rset = view->regsets + rsn; int err; if (write) { for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(reg_mem + reg_map->usr_offs, gdb_mem + reg_map->gdb_offs, reg_map->gdb_size); } err = rset->set(task, rset, 0, reg_size, reg_mem, NULL); } else { err = rset->get(task, rset, 0, reg_size, reg_mem, NULL); if (err) goto ret; for (; reg_cnt--; ++reg_map) { if (reg_map->rs_setno != rsn) continue; memcpy(gdb_mem + reg_map->gdb_offs, reg_mem + reg_map->usr_offs, reg_map->gdb_size); } } ret: return err; } #define GDB_REGS_SIZE(regmap) \ (regmap[ARRAY_SIZE(regmap)-1].gdb_size + \ regmap[ARRAY_SIZE(regmap)-1].gdb_offs) struct regs_buf { unsigned char gdb_mem[1024]; union { struct user_regs_struct user_regs_struct; struct user_i387_struct user_i387_struct; }; }; static int ugdb_rw_all_regs(struct task_struct *task, struct regs_buf *regs_buf, bool write) { const struct user_regset_view *view; int ret; #define RW(rsn, user, rmap) \ rw_one_regset(task, rsn, view, \ ®s_buf->user, sizeof(regs_buf->user), \ rmap, ARRAY_SIZE(rmap), regs_buf->gdb_mem, \ write) view = task_user_regset_view(task); switch (view->e_machine) { case EM_X86_64: // XXX: even this needs fixup. There is no ->fs_base in gdb's set // of regs, it is wrongly initialized as 0 and putreg()->do_arch_prctl() // changes fs. Later, gdb seems to never use G if P works. ret = RW(REGSET_GENERAL, user_regs_struct, gdb_regmap_64); if (ret) break; // XXX: needs fixup, see i387_fxsave_to_cache/i387_cache_to_fxsave. // At least xfpregs_get() is safe even if result is not correct. if (!write) ret = RW(REGSET_FP, user_i387_struct, gdb_regmap_64); if (ret) break; ret = GDB_REGS_SIZE(gdb_regmap_64); break; default: ret = -EIO; } #undef RW return ret; } static const char *handle_get_all_regs(struct ugdb *ugdb) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, false); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; if (size > sizeof(regs_buf->gdb_mem)) { WARN_ON(1); goto err; } if (pb_room(&ugdb->u_pbuf) < 3 + size * 2) { WARN_ON(1); goto err; } pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, regs_buf->gdb_mem, size); pb_end(&ugdb->u_pbuf); ret = NULL; err: kfree(regs_buf); out: return ret; } static const char *handle_set_all_regs(struct ugdb *ugdb, char *cmd, int len) { struct regs_buf *regs_buf; struct utrace_examiner exam; struct task_struct *task; const char *ret = "E01"; int size; printk(KERN_INFO "XXX: $G command, why?\n"); cmd += 1; len -= 1; if (len & 1) goto out; len /= 2; if (unhex(cmd, len)) goto out; regs_buf = kzalloc(sizeof(*regs_buf), GFP_KERNEL); if (!regs_buf) goto out; memcpy(regs_buf->gdb_mem, cmd, len); task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; size = ugdb_rw_all_regs(task, regs_buf, true); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (size < 0) goto err; WARN_ON(size != len); ret = "OK"; err: kfree(regs_buf); out: return ret; } static typeof(access_process_vm) *u_access_process_vm; static const char *handle_readmem(struct ugdb *ugdb, char *cmd) { struct utrace_examiner exam; struct task_struct *task; unsigned long addr, size; unsigned char *mbuf; int copied; if (sscanf(cmd, "m%lx,%lx", &addr, &size) != 2) goto err; size = min_t(unsigned long, size, pb_max_bs_size(&ugdb->u_pbuf)); if (!size) goto err; mbuf = pb_alloc_bs(&ugdb->u_pbuf, size); if (WARN_ON(!mbuf)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; copied = u_access_process_vm(task, addr, mbuf, size, 0); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (copied > 0 ) { pb_start(&ugdb->u_pbuf); pb_putbs(&ugdb->u_pbuf, mbuf, copied); pb_end(&ugdb->u_pbuf); return NULL; } err: return "E01"; } static const char *handle_writemem(struct ugdb *ugdb, char *cmd, int len) { unsigned long addr, size; unsigned int skip, written; struct utrace_examiner exam; struct task_struct *task; if (sscanf(cmd, "M%lx,%lx:%n", &addr, &size, &skip) != 2) goto err; cmd += skip; len -= skip; if (len != 2*size || !size) goto err; if (unhex(cmd, size)) goto err; task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto err; written = u_access_process_vm(task, addr, cmd, size, 1); if (ugdb_finish_examine(ugdb, &exam)) goto err; if (written == size) return "OK"; err: return "E01"; } static int ugdb_siginfo_rw(struct ugdb *ugdb, siginfo_t *info, bool write) { struct task_struct *task; struct utrace_examiner exam; struct sighand_struct *sighand; siginfo_t *t_siginfo; int ret = -EINVAL; /* * ugdb_prepare_examine() is overkill, but otherwise we can't * assume task_is_traced(), and this is what ensures we can * safely read/write ->t_siginfo which points to task's stack. */ task = ugdb_prepare_examine(ugdb, &exam); if (!task) goto out; /* OK, task_struct can't go away, but ->sighand can. */ rcu_read_lock(); sighand = rcu_dereference(task->sighand); if (!sighand) goto unlock_rcu; spin_lock_irq(&sighand->siglock); if (!task_is_traced(task)) goto unlock_siglock; t_siginfo = ugdb->u_cur_hg->t_siginfo; if (!t_siginfo) goto unlock_siglock; if (write) *t_siginfo = *info; else *info = *t_siginfo; ret = 0; unlock_siglock: spin_unlock_irq(&sighand->siglock); unlock_rcu: rcu_read_unlock(); ugdb_finish_examine(ugdb, &exam); out: return ret; } static const char *handle_siginfo_read(struct ugdb *ugdb, char *cmd) { unsigned int off, len; siginfo_t info; if (sscanf(cmd, "%x,%x", &off, &len) != 2) goto err; if (off >= sizeof(info)) goto err; if (len > sizeof(info) || off + len > sizeof(info)) len = sizeof(info) - off; if (ugdb_siginfo_rw(ugdb, &info, false)) goto err; if (pb_qfer(&ugdb->u_pbuf, &info + off, len, (off + len < sizeof(info)))) goto err; // XXX: Oh. we also need x86_siginfo_fixup(). how ugly. return NULL; err: return "E01"; } // ----------------------------------------------------------------------------- #define EQ(cmd, str) \ (strncmp((cmd), (str), sizeof(str)-1) ? false : \ ((cmd) += sizeof(str)-1, true)) static const char *handle_qfer(struct ugdb *ugdb, char *cmd) { const char *rc = "E01"; if (EQ(cmd, "siginfo:")) { if (EQ(cmd, "read::")) rc = handle_siginfo_read(ugdb, cmd); } return rc; } static void handle_command(struct ugdb *ugdb, char *cmd, int len) { struct pbuf *pb = &ugdb->u_pbuf; const char *rc = ""; switch (cmd[0]) { case '!': case '?': rc = "OK"; break; case 'H': rc = handle_set_cur(ugdb, cmd + 1); break; case 'T': rc = handle_ck_alive(ugdb, cmd + 1); break; case 'D': rc = handle_detach(ugdb, cmd + 1); break; case 'g': rc = handle_get_all_regs(ugdb); break; case 'G': rc = handle_set_all_regs(ugdb, cmd, len); break; case 'p': rc = handle_get_reg(ugdb, cmd, len); break; case 'P': rc = handle_set_reg(ugdb, cmd, len); break; case 'm': rc = handle_readmem(ugdb, cmd); break; case 'M': rc = handle_writemem(ugdb, cmd, len); break; case 'C': case 'c': case 'S': case 's': rc = handle_c(ugdb, cmd); break; case 'z': case 'Z': rc = handle_z(ugdb, cmd, len); break; case 'q': if (EQ(cmd, "qSupported")) { if (!strstr(cmd, "multiprocess+")) { printk(KERN_INFO "ugdb: can't work without multiprocess\n"); ugdb->u_err = -EPROTONOSUPPORT; } pb_packf(&ugdb->u_pbuf, "PacketSize=%x;%s", PACKET_SIZE, "QStartNoAckMode+;QNonStop+;multiprocess+;" "QPassSignals+;qXfer:siginfo:read+"); rc = NULL; } else if (EQ(cmd, "qfThreadInfo")) { rc = handle_thread_info(ugdb, true); } else if (EQ(cmd, "qsThreadInfo")) { rc = handle_thread_info(ugdb, false); } else if (EQ(cmd, "qXfer:")) { rc = handle_qfer(ugdb, cmd); } else if (EQ(cmd, "qTStatus")) { rc = "T0"; } break; case 'Q': if (EQ(cmd, "QStartNoAckMode")) { ugdb->u_no_ack = true; rc = "OK"; } else if (EQ(cmd, "QNonStop:")) { if (*cmd != '1') { printk(KERN_INFO "ugdb: all-stop is not implemented.\n"); ugdb->u_err = -EPROTONOSUPPORT; } rc = "OK"; } else if (EQ(cmd, "QPassSignals:")) { rc = handle_qpass_signals(ugdb, cmd); } break; case 'v': if (EQ(cmd, "vAttach;")) { rc = handle_vattach(ugdb, cmd); } else if (EQ(cmd, "vStopped")) { rc = handle_vstopped(ugdb); } else if (EQ(cmd, "vCont")) { rc = handle_vcont(ugdb, cmd); } break; default: ; } if (rc) pb_packs(pb, rc); } static void process_commands(struct ugdb *ugdb) { char *cmds = ugdb->u_cbuf; int todo = ugdb->u_clen; if (o_remote_debug) printk(KERN_INFO "=> %.*s\n", ugdb->u_clen, ugdb->u_cbuf); while (todo) { char first; char *c_cmd, *c_end; int c_len; first = *cmds++; todo--; switch (first) { default: printk(KERN_INFO "XXX: unknown chr %02x\n", first); pb_putc(&ugdb->u_pbuf, '-'); break; case '-': printk(KERN_INFO "XXX: got NACK!\n"); ugdb->u_err = -EPROTO; case '+': break; case 0x3: printk(KERN_INFO "XXX: unexpected CTRL-C\n"); break; case '$': c_cmd = cmds; c_end = strnchr(c_cmd, todo, '#'); c_len = c_end ? c_end - cmds : -1; if (c_len < 0 || todo < c_len + 3) { printk(KERN_INFO "XXX: can't find '#cs'\n"); ++todo; --cmds; goto out; } // XXX: verify checksum ? todo -= c_len + 3; cmds += c_len + 3; *c_end = 0; if (!ugdb->u_no_ack) pb_putc(&ugdb->u_pbuf, '+'); handle_command(ugdb, c_cmd, c_len); } } out: ugdb->u_clen = todo; if (todo && cmds > ugdb->u_cbuf) memmove(ugdb->u_cbuf, cmds, todo); } // ----------------------------------------------------------------------------- static int xxx_tinfo(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 0; mutex_lock(&ugdb->u_mutex); thread = ugdb_advance_tinfo(ugdb); if (thread) tid = thread->t_tid; mutex_unlock(&ugdb->u_mutex); return tid; } static int do_stop_thread(struct ugdb_thread *thread, void *arg) { ugdb_stop_thread(thread, arg != NULL); return 0; } static int do_cont_thread(struct ugdb_thread *thread, void *arg) { ugdb_cont_thread(thread, arg != NULL, false); return 0; } static int xxx_sc_threads(struct ugdb *ugdb, int tid, bool sc) { void *arg = NULL; int pid = 0; int ret; if (tid < 0) { pid = -tid; tid = -1; arg = (void*)1; } mutex_lock(&ugdb->u_mutex); ret = ugdb_do_each_thread(ugdb, pid, tid, sc ? do_stop_thread : do_cont_thread, arg); mutex_unlock(&ugdb->u_mutex); return ret; } static int xxx_stop(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, true); } static int xxx_cont(struct ugdb *ugdb, int tid) { return xxx_sc_threads(ugdb, tid, false); } static int xxx_get_stopped(struct ugdb *ugdb) { struct ugdb_thread *thread; int tid = 1; if (ugdb->u_stop_state == U_STOP_IDLE) return -1; if (ugdb->u_stop_state == U_STOP_PENDING) tid = 1000; thread = ugdb_next_stopped(ugdb); if (!thread) return 0; return tid * thread->t_tid; } static int xxx_show_all(struct ugdb *ugdb) { struct ugdb_process *process; struct ugdb_thread *thread; printk(KERN_INFO "SHOW start ----------------------------------------\n"); mutex_lock(&ugdb->u_mutex); list_for_each_entry(process, &ugdb->u_processes, p_processes) { printk(KERN_INFO "PROC: %x\n", process->p_pid); list_for_each_entry(thread, &process->p_threads, t_threads) { printk(KERN_INFO " T: %x %p; %p %p\n", thread->t_tid, thread, thread->t_spid, pid_task(thread->t_spid, PIDTYPE_PID)); } } mutex_unlock(&ugdb->u_mutex); printk(KERN_INFO "SHOW end ----------------------------------------\n"); return 0; } static long ugdb_f_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ugdb *ugdb = file->private_data; // XXX: otherwise gdb->get_tty_state(TCGETS, TCSETS, TCFLSH) complains int ret = 0; // XXX: temporary debugging hooks, ignore. switch (cmd) { case 0x666 + 0: ret = ugdb_attach(ugdb, arg); break; case 0x666 + 1: ret = ugdb_detach(ugdb, arg); break; case 0x666 + 2: ret = xxx_tinfo(ugdb); break; case 0x666 + 3: ret = xxx_stop(ugdb, arg); break; case 0x666 + 4: ret = xxx_cont(ugdb, arg); break; case 0x666 + 5: ret = xxx_get_stopped(ugdb); break; case 0x666 + 6: ret = xxx_show_all(ugdb); break; } return ret; } static unsigned int ugdb_f_poll(struct file *file, poll_table *wait) { struct ugdb *ugdb = file->private_data; unsigned int mask; poll_wait(file, &ugdb->u_wait, wait); mask = (POLLOUT | POLLWRNORM); if (pb_size(&ugdb->u_pbuf) || ugdb->u_stop_state == U_STOP_PENDING) mask |= (POLLIN | POLLRDNORM); if (ugdb->u_err) mask |= POLLERR; return mask; } static ssize_t ugdb_f_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; struct pbuf *pb = &ugdb->u_pbuf; if (ugdb->u_err) return ugdb->u_err; if (ugdb->u_stop_state == U_STOP_PENDING) ugdb_report_stopped(ugdb, true); if (pb_size(pb) > count) { printk(KERN_INFO "XXX: short read %d %ld\n", pb_size(pb), count); } return pb_copy_to_user(pb, ubuf, count); } static ssize_t ugdb_f_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct ugdb *ugdb = file->private_data; if (ugdb->u_err) return ugdb->u_err; if (count > PACKET_SIZE - ugdb->u_clen) { count = PACKET_SIZE - ugdb->u_clen; printk("XXX: write(%ld,%d) enospc\n", count, ugdb->u_clen); if (1) return ugdb->u_err = -ENOSPC; } if (copy_from_user(ugdb->u_cbuf + ugdb->u_clen, ubuf, count)) return -EFAULT; ugdb->u_clen += count; process_commands(ugdb); return count; } static int ugdb_f_open(struct inode *inode, struct file *file) { nonseekable_open(inode, file); file->private_data = ugdb_create(); return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; } static int ugdb_f_release(struct inode *inode, struct file *file) { ugdb_destroy(file->private_data); return 0; } static const struct file_operations ugdb_f_ops = { .open = ugdb_f_open, .unlocked_ioctl = ugdb_f_ioctl, .poll = ugdb_f_poll, .read = ugdb_f_read, .write = ugdb_f_write, .release = ugdb_f_release, }; #include struct kallsyms_sym { const char *name; unsigned long addr; }; static int kallsyms_on_each_symbol_cb(void *data, const char *name, struct module *mod, unsigned long addr) { struct kallsyms_sym *sym = data; if (strcmp(name, sym->name)) return 0; sym->addr = addr; return 1; } // XXX: kallsyms_lookup_name() is not exported in 2.6.32 static bool lookup_unexported(void) { struct kallsyms_sym sym; sym.name = "access_process_vm"; if (!kallsyms_on_each_symbol(kallsyms_on_each_symbol_cb, &sym)) goto err; u_access_process_vm = (void*)sym.addr; sym.name = "arch_ptrace"; if (!kallsyms_on_each_symbol(kallsyms_on_each_symbol_cb, &sym)) goto err; u_arch_ptrace = (void*)sym.addr; return true; err: printk(KERN_ERR "ugdb: can't lookup %s\n", sym.name); return false; } #define PROC_NAME "ugdb" struct proc_dir_entry *ugdb_pde; static int __init ugdb_init(void) { if (!lookup_unexported()) return -ESRCH; ugdb_pde = proc_create(PROC_NAME, S_IFREG|S_IRUGO|S_IWUGO, NULL, &ugdb_f_ops); if (!ugdb_pde) return -EBADF; return 0; } static void __exit ugdb_exit(void) { remove_proc_entry(PROC_NAME, NULL); } MODULE_LICENSE("GPL"); module_init(ugdb_init); module_exit(ugdb_exit); From roland at redhat.com Tue Nov 16 20:02:26 2010 From: roland at redhat.com (Roland McGrath) Date: Tue, 16 Nov 2010 12:02:26 -0800 (PST) Subject: gdbstub initial code, v16 In-Reply-To: Oleg Nesterov's message of Monday, 15 November 2010 20:05:37 +0100 <20101115190537.GA15725@redhat.com> References: <20101115190537.GA15725@redhat.com> Message-ID: <20101116200226.BDD7B40147@magilla.sf.frob.com> > Well. I can't say this change is good. Because ugdb uses (unexported) > arch_ptrace() to set debugregs in a very much x86-specific way. However, > I do not see what else can I do. That kludge is unworkable in several ways. It is just not worth pursuing. Just use hw_breakpoint on kernels that have it, and don't try to support the feature on kernels that don't. > Say, should I implement vRun? From the very beginnig, I hate the idea > to exec the target from kernel space, but otoh I'm afraid this is > important for gdb users. We've also vaguely discussed doing some hybrid solution where gdb does something different for "run". If you can do a kludge to implement vRun fairly quickly and it works OK--including that it remains possible for ugdb to be a module--then go ahead. If that is too ungainly, or is just plain infeasible (which I think it might be), then don't bend over backwards for it. We may have reached the end of what it's possible to get done at all sensibly without more active involvement from the GDB team. Thanks, Roland From P.S.Gaonkar at student.tudelft.nl Tue Nov 30 21:36:37 2010 From: P.S.Gaonkar at student.tudelft.nl (Pavan) Date: Tue, 30 Nov 2010 22:36:37 +0100 Subject: Need help on utrace Message-ID: <4CF56E65.4080105@student.tudelft.nl> Hi, I am new to utrace and want to know is there any way i can get an Linux ISO image with utrace ? Please help. I need it for my coursework. Thanking in advance. Regards Pavan From mjw at redhat.com Wed Dec 1 09:42:06 2010 From: mjw at redhat.com (Mark Wielaard) Date: Wed, 01 Dec 2010 10:42:06 +0100 Subject: Need help on utrace In-Reply-To: <4CF56E65.4080105@student.tudelft.nl> References: <4CF56E65.4080105@student.tudelft.nl> Message-ID: <1291196526.3301.1.camel@springer.wildebeest.org> On Tue, 2010-11-30 at 22:36 +0100, Pavan wrote: > I am new to utrace and want to know is there any way i can get an > Linux ISO image with utrace ? Please help. I need it for my coursework. utrace is included in a couple of distros by default. Fedora, CentOS, Red Hat Enterprise Linux and OpenSuse (you need the kernel-trace package) come with utrace build in. From P.S.Gaonkar at student.tudelft.nl Wed Dec 1 13:46:58 2010 From: P.S.Gaonkar at student.tudelft.nl (Pavan) Date: Wed, 01 Dec 2010 14:46:58 +0100 Subject: Need information on utrace based ptrace patch Message-ID: <4CF651D2.9030905@student.tudelft.nl> Hi, Can some one please provide me information on the utrace based ptrace patch ? Regards Pavan From P.S.Gaonkar at student.tudelft.nl Thu Dec 2 20:15:52 2010 From: P.S.Gaonkar at student.tudelft.nl (Pavan) Date: Thu, 02 Dec 2010 21:15:52 +0100 Subject: Need information on utrace based user space API Message-ID: <4CF7FE78.4060501@student.tudelft.nl> Hi, I am new to utrace and want to use it for instruction tracing user space applications. Can some one please help me with this ? I have read about uprobes, but am unable to get more details on how can i get it and how can i use it. Any help will be really appreciated. Regards Pavan From mjw at redhat.com Fri Dec 3 08:55:13 2010 From: mjw at redhat.com (Mark Wielaard) Date: Fri, 03 Dec 2010 09:55:13 +0100 Subject: Need information on utrace based user space API In-Reply-To: <4CF7FE78.4060501@student.tudelft.nl> References: <4CF7FE78.4060501@student.tudelft.nl> Message-ID: <1291366515.2218.8.camel@hermans.wildebeest.org> On Thu, 2010-12-02 at 21:15 +0100, Pavan wrote: > I am new to utrace and want to use it for instruction tracing user > space applications. Can some one please help me with this ? I have read > about uprobes, but am unable to get more details on how can i get it and > how can i use it. Any help will be really appreciated. Systemtap has an probe process().insn[.block] that is based on UTRACE_SINGLESTEP / BLOCKSTEP: http://sourceware.org/systemtap/langref/Probe_points.html#SECTION00065700000000000000 The systemtap source code also contains an (actually two) implementation of uprobes based on utrace: http://sourceware.org/git/?p=systemtap.git;a=tree;f=runtime/uprobes2 Also look in the archives of this list and/or the lkml mailinglist for another version not currently based on utrace. Cheers, Mark From hpatel05 at gmail.com Tue Dec 7 05:04:20 2010 From: hpatel05 at gmail.com (h patel) Date: Tue, 7 Dec 2010 10:34:20 +0530 Subject: Kernel crash after enabling utrace Message-ID: Hi, I am seeing kernel crash after enabling utrace for systemtap user space support. My setup is : - Cross Instrumentation with user space trace support required. - Host : Running CentOS 5.4 with 2.6.18-164.el5 i686 - Target : Self compiled Kernel 2.6.32.10 i686 I applied three utrace patches on target kernel and enabled EXPERIMENTAL and UTRACE flags along with other systemtap flags. After doing this, whenever I run systemtap kernel profiling script, it crashes with following on serial. Am I missing any step ? (Also, after enabling EXPERIMENTAL, I saw some memory model related flags are enabled automatically which I believe don't affect kernel. ) Thanks, hp trace : BUG: unable to handle kernel NULL pointer dereference at 00000003 IP: [] __list_add+0xa/0x5c *pdpt = 0000000036814001 *pde = 0000000000000000 Oops: 0000 [#1] SMP last sysfs file: /sys/module/xt_tcpudp/sections/.text Modules linked in: topsys xt_mark xt_MARK xt_TCPMSS ipt_REJECT xt_tcpudp iptable _filter iptable_mangle ipt_vlan_routing ip_gre 8021q atsfilter atsvif force_frag ipt_CLSFY ip_tables x_tables rebrid_ioctl rebridging wncreg reg reg_table kcomm 2(P) meru_debug meru_util iTCO_wdt iTCO_vendor_support bonding igb Pid: 705, comm: monit Tainted: P W (2.6.32.10 #20) To Be Filled By O.E.M . EIP: 0060:[] EFLAGS: 00010286 CPU: 0 EIP is at __list_add+0xa/0x5c EAX: f1c797dc EBX: f1c79778 ECX: ffffffff EDX: f1c30660 ESI: f1c30660 EDI: f1c797dc EBP: f25c9f54 ESP: f25c9f48 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 Process monit (pid: 705, ti=f25c8000 task=f756d350 task.ti=f25c8000) Stack: f1c79778 f1c30648 f1c79778 f25c9f64 c04842d4 f1c79778 f1c30648 f25c9f74 <0> c048438b 00000002 f2347d18 f25c9f50 c05b5538 f25c9fac c05b657e 00000002 <0> 00000001 00000000 00000002 00000001 00000000 00000000 c04e68c8 b7806424 Call Trace: [] ? __d_instantiate+0x1b/0xaa [] ? d_instantiate+0x28/0x36 [] ? sock_attach_fd+0x5f/0xab [] ? sys_socketcall+0x55/0x178 [] ? trace_hardirqs_on_thunk+0xc/0x10 [] ? sysenter_do_call+0x12/0x36 Code: f3 ff 83 c4 14 8b 13 8b 43 04 89 42 04 89 10 c7 43 04 00 02 20 00 c7 03 00 01 10 00 8b 5d fc c9 c3 55 89 e5 57 89 c7 56 89 d6 53 <8b> 41 04 89 cb 39 d0 74 17 51 50 52 68 f1 51 72 c0 6a 1a 68 a6 EIP: [] __list_add+0xa/0x5c SS:ESP 0068:f25c9f48 CR2: 0000000000000003 ---[ end trace 7c8b87fe60b0346b ]--- From oleg at redhat.com Fri Dec 10 11:53:36 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:53:36 +0100 Subject: [PATCH 0/5] ptrace-utrace: fix exit_ptrace() vs ptrace_report_signal() races Message-ID: <20101210115336.GA26863@redhat.com> In short: exit_ptrace()->ptrace_detach_task() is very wrong when it tries to detach the !stopped tracee, we can not trust get_stop_event() in this case. This means that in the case like ptrace(PTRACE_CONT, ..., SIGXXX); exit(); // ---> calls ptrace_detach_task() the tracee can miss SIGXXX if ptrace_detach_task() does utrace_control(UTRACE_DETACH) before the tracee calls ->report_signal(). 5/5 is the actual fix. 1-4 are preparations to simplify the review and document the changes. Oleg. From oleg at redhat.com Fri Dec 10 11:54:00 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:54:00 +0100 Subject: [PATCH 1/5] ptrace-utrace: ptrace_reuse_engine()->utrace_barrier() should ignore ERESTARTSYS In-Reply-To: <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101210115400.GB26863@redhat.com> I missed that ptrace_reuse_engine()->utrace_barrier() can return ERESTARTSYS if signal_pending(). Unfortunately, it is too late to abort and restart this syscall, we already changed ctx->resume. Introduce utrace_barrier_uninterruptible() which calls utrace_barrier() and ignores ERESTARTSYS. Note that we do schedule_timeout_uninterruptible() to avoid the livelock. utrace_barrier()->schedule_timeout_interruptible() is nop in this case. This helper will have another user, exit_ptrace()->ptrace_detach_task(), it obviously can't restart too. Also, improve (and fix) the debugging engine->ops checks. In theory the tracee can exit right after utrace_barrier() succeeds, this can lead to the false warning. Signed-off-by: Oleg Nesterov --- kernel/ptrace-utrace.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) --- kstub/kernel/ptrace-utrace.c~1_fix_reuse_barrier 2010-09-20 03:43:28.000000000 +0200 +++ kstub/kernel/ptrace-utrace.c 2010-09-20 03:53:30.000000000 +0200 @@ -103,6 +103,19 @@ static struct utrace_engine *ptrace_look &ptrace_utrace_ops, NULL); } +static int utrace_barrier_uninterruptible(struct task_struct *target, + struct utrace_engine *engine) +{ + for (;;) { + int err = utrace_barrier(target, engine); + + if (err != -ERESTARTSYS) + return err; + + schedule_timeout_uninterruptible(1); + } +} + static struct utrace_engine * ptrace_reuse_engine(struct task_struct *tracee) { @@ -129,12 +142,16 @@ ptrace_reuse_engine(struct task_struct * if (!err || err == -EINPROGRESS) { ctx->resume = UTRACE_RESUME; /* synchronize with ptrace_report_signal() */ - err = utrace_barrier(tracee, engine); + err = utrace_barrier_uninterruptible(tracee, engine); } - WARN_ON(!err != (engine->ops == &ptrace_utrace_ops)); - if (!err) + if (!err) { + WARN_ON(engine->ops != &ptrace_utrace_ops && + !tracee->exit_state); return engine; + } + + WARN_ON(engine->ops == &ptrace_utrace_ops); } utrace_engine_put(engine); From oleg at redhat.com Fri Dec 10 11:54:21 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:54:21 +0100 Subject: [PATCH 2/5] ptrace-utrace: the tracee shouldn never change ctx->resume In-Reply-To: <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101210115421.GC26863@redhat.com> ptrace_report_syscall_exit() is the only callback which changes ctx->resume. Remove this, this is unnecessary. We know that ptrace_report_signal() will be called before any other callback, and UTRACE_SIGNAL_HANDLER is not possible. With this change the tracer owns ctx->resume, it can always change it safely even if the tracee is not stopped (implicit detach). Signed-off-by: Oleg Nesterov --- kernel/ptrace-utrace.c | 1 - 1 file changed, 1 deletion(-) --- kstub/kernel/ptrace-utrace.c~2_tracer_owns_resume 2010-09-20 03:53:30.000000000 +0200 +++ kstub/kernel/ptrace-utrace.c 2010-09-20 03:53:31.000000000 +0200 @@ -429,7 +429,6 @@ static u32 ptrace_report_syscall_exit(u3 if (ctx->resume != UTRACE_RESUME) { WARN_ON(ctx->resume != UTRACE_BLOCKSTEP && ctx->resume != UTRACE_SINGLESTEP); - ctx->resume = UTRACE_RESUME; ctx->signr = SIGTRAP; return UTRACE_INTERRUPT; From oleg at redhat.com Fri Dec 10 11:54:46 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:54:46 +0100 Subject: [PATCH 3/5] ptrace-utrace: don't assume resume != UTRACE_RESUME means stepping In-Reply-To: <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101210115446.GD26863@redhat.com> No functional changes. Currently ptrace_report_syscall_exit() and ptrace_report_signal(UTRACE_SIGNAL_HANDLER) can see either UTRACE_RESUME or UTRACE_BLOCKSTEP/UTRACE_SINGLESTEP, but we are going to change this. Change the code to not assume that resume != UTRACE_RESUME means stepping. Add the trivial helper, is_step_resume(), which does the check. Signed-off-by: Oleg Nesterov --- kernel/ptrace-utrace.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) --- kstub/kernel/ptrace-utrace.c~3_resume_step_helper 2010-09-20 03:53:31.000000000 +0200 +++ kstub/kernel/ptrace-utrace.c 2010-09-20 03:53:31.000000000 +0200 @@ -418,6 +418,11 @@ static u32 ptrace_report_syscall_entry(u return UTRACE_SYSCALL_RUN | UTRACE_STOP; } +static inline bool is_step_resume(enum utrace_resume_action resume) +{ + return resume == UTRACE_BLOCKSTEP || resume == UTRACE_SINGLESTEP; +} + static u32 ptrace_report_syscall_exit(u32 action, struct utrace_engine *engine, struct pt_regs *regs) { @@ -426,10 +431,7 @@ static u32 ptrace_report_syscall_exit(u3 if (ptrace_event_pending(ctx)) return UTRACE_STOP; - if (ctx->resume != UTRACE_RESUME) { - WARN_ON(ctx->resume != UTRACE_BLOCKSTEP && - ctx->resume != UTRACE_SINGLESTEP); - + if (is_step_resume(ctx->resume)) { ctx->signr = SIGTRAP; return UTRACE_INTERRUPT; } @@ -517,10 +519,7 @@ static u32 ptrace_report_signal(u32 acti if (WARN_ON(ctx->siginfo)) ctx->siginfo = NULL; - if (resume != UTRACE_RESUME) { - WARN_ON(resume != UTRACE_BLOCKSTEP && - resume != UTRACE_SINGLESTEP); - + if (is_step_resume(resume)) { set_stop_code(ctx, PTRACE_EVENT_SIGTRAP); return UTRACE_STOP | UTRACE_SIGNAL_IGN; } From oleg at redhat.com Fri Dec 10 11:55:10 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:55:10 +0100 Subject: [PATCH 4/5] ptrace-utrace: introduce PTRACE_O_DETACHED to mark the self-detaching engine In-Reply-To: <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101210115510.GE26863@redhat.com> Introduce PTRACE_O_DETACHED to mark the almost-detached engine as reusable for ptrace_reuse_engine(). Currently ptrace_reuse_engine() just checks ctx->resume == UTRACE_DETACH, but we are going to change ptrace_detach_task() to play with the tracee after setting ctx->resume == UTRACE_DETACH and thus we need another method to indicate that this engine is going to detach itself. Note that we set PTRACE_O_DETACHED after ptrace_wake_up()->utrace_control() and the possible new tracer does utrace_set_events() before it changes ctx->resume. This means that we do not need the barriers but can rely on utrace locking. Signed-off-by: Oleg Nesterov --- kernel/ptrace-utrace.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) --- kstub/kernel/ptrace-utrace.c~4_o_reusable 2010-09-20 03:53:31.000000000 +0200 +++ kstub/kernel/ptrace-utrace.c 2010-09-20 03:53:32.000000000 +0200 @@ -67,6 +67,7 @@ struct ptrace_context { #define PT_UTRACED 0x00001000 #define PTRACE_O_SYSEMU 0x100 +#define PTRACE_O_DETACHED 0x200 #define PTRACE_EVENT_SYSCALL (1 << 16) #define PTRACE_EVENT_SIGTRAP (2 << 16) @@ -128,7 +129,7 @@ ptrace_reuse_engine(struct task_struct * return engine; ctx = ptrace_context(engine); - if (unlikely(ctx->resume == UTRACE_DETACH)) { + if (unlikely(ctx->options == PTRACE_O_DETACHED)) { /* * Try to reuse this self-detaching engine. * The only caller which can hit this case is ptrace_attach(), @@ -264,12 +265,14 @@ static void ptrace_detach_task(struct ta bool voluntary = (sig >= 0); struct utrace_engine *engine = ptrace_lookup_engine(tracee); enum utrace_resume_action action = UTRACE_DETACH; + struct ptrace_context *ctx; if (unlikely(IS_ERR(engine))) return; + ctx = ptrace_context(engine); + if (sig) { - struct ptrace_context *ctx = ptrace_context(engine); switch (get_stop_event(ctx)) { case PTRACE_EVENT_SYSCALL: @@ -287,6 +290,10 @@ static void ptrace_detach_task(struct ta } ptrace_wake_up(tracee, engine, action, voluntary); + + if (action != UTRACE_DETACH) + ctx->options = PTRACE_O_DETACHED; + utrace_engine_put(engine); } @@ -774,7 +781,7 @@ void exit_ptrace(struct task_struct *tra static int ptrace_set_options(struct task_struct *tracee, struct utrace_engine *engine, long data) { - BUILD_BUG_ON(PTRACE_O_MASK & PTRACE_O_SYSEMU); + BUILD_BUG_ON(PTRACE_O_MASK & (PTRACE_O_SYSEMU | PTRACE_O_DETACHED)); ptrace_set_events(tracee, engine, data & PTRACE_O_MASK); return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; From oleg at redhat.com Fri Dec 10 11:55:32 2010 From: oleg at redhat.com (Oleg Nesterov) Date: Fri, 10 Dec 2010 12:55:32 +0100 Subject: [PATCH 5/5] ptrace-utrace: fix exit_ptrace() vs ptrace_report_signal() races In-Reply-To: <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101210115532.GF26863@redhat.com> Finally, the actual fix. ptrace_detach_task(sig => -1) is very buggy. Somehow I completely forgot that implicit detach can race with the running tracee. Depending on how exactly it races with ptrace_report_signal() we can have the following problems: 1) If the tracer exits right after ptrace(PTRACE_CONT, SIGXXX) the tracee can miss this signal. 2) the tracee can report a signal and stop after it was already detached. Change ptrace_detach_task(sig => -1) to set ctx->resume = UTRACE_DETACH before anything else, change ptrace_report_signal() to check ctx->resume before reporting a signal. This fixes the 2nd problem. To fix the 1st problem, change !explicit case to check ->siginfo != NULL instead of relying on get_stop_event() which can't work with the running tracee. Reported-by: Glen Johnson Signed-off-by: Oleg Nesterov --- kernel/ptrace-utrace.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) --- kstub/kernel/ptrace-utrace.c~5_implicit_detach_races 2010-09-20 03:53:32.000000000 +0200 +++ kstub/kernel/ptrace-utrace.c 2010-09-20 03:53:32.000000000 +0200 @@ -262,7 +262,7 @@ static void ptrace_detach_task(struct ta * If true, the caller is PTRACE_DETACH, otherwise * the tracer detaches implicitly during exit. */ - bool voluntary = (sig >= 0); + bool explicit = (sig >= 0); struct utrace_engine *engine = ptrace_lookup_engine(tracee); enum utrace_resume_action action = UTRACE_DETACH; struct ptrace_context *ctx; @@ -272,24 +272,46 @@ static void ptrace_detach_task(struct ta ctx = ptrace_context(engine); - if (sig) { + if (!explicit) { + int err; + /* + * We are going to detach, the tracee can be running. + * Ensure ptrace_report_signal() won't report a signal. + */ + ctx->resume = UTRACE_DETACH; + err = utrace_barrier_uninterruptible(tracee, engine); + + if (!err && ctx->siginfo) { + /* + * The tracee has already reported a signal + * before utrace_barrier(). + * + * Resume it like we do in PTRACE_EVENT_SIGNAL + * case below. The difference is that we can race + * with ptrace_report_signal() if the tracee is + * running but this doesn't matter. In any case + * UTRACE_SIGNAL_REPORT must be pending and it + * can return nothing but UTRACE_DETACH. + */ + action = UTRACE_RESUME; + } + + } else if (sig) { switch (get_stop_event(ctx)) { case PTRACE_EVENT_SYSCALL: - if (voluntary) - send_sig_info(sig, SEND_SIG_PRIV, tracee); + send_sig_info(sig, SEND_SIG_PRIV, tracee); break; case PTRACE_EVENT_SIGNAL: - if (voluntary) - ctx->signr = sig; + ctx->signr = sig; ctx->resume = UTRACE_DETACH; action = UTRACE_RESUME; break; } } - ptrace_wake_up(tracee, engine, action, voluntary); + ptrace_wake_up(tracee, engine, action, explicit); if (action != UTRACE_DETACH) ctx->options = PTRACE_O_DETACHED; @@ -553,6 +575,11 @@ static u32 ptrace_report_signal(u32 acti } WARN_ON(ctx->siginfo); + + /* Raced with the exiting tracer ? */ + if (resume == UTRACE_DETACH) + return action; + ctx->siginfo = info; /* * ctx->siginfo points to the caller's stack. From roland at redhat.com Sat Dec 11 01:55:52 2010 From: roland at redhat.com (Roland McGrath) Date: Fri, 10 Dec 2010 17:55:52 -0800 (PST) Subject: [PATCH 0/5] ptrace-utrace: fix exit_ptrace() vs ptrace_report_signal() races In-Reply-To: Oleg Nesterov's message of Friday, 10 December 2010 12:53:36 +0100 <20101210115336.GA26863@redhat.com> References: <20101210115336.GA26863@redhat.com> Message-ID: <20101211015552.BFD05400CE@magilla.sf.frob.com> I've merged these patches to the utrace-ptrace branch, now merged up to 2.6.37-rc5, and also the 2.6.34 and 2.6.35 backport branches. The 2.6.33 backport branch is no longer being maintained. I didn't update the 2.6.36 backport branch and probably won't maintain it unless some Fedora release starts using that kernel version (rawhide is already on 2.6.37-rc5 now). Thanks, Roland