00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "j_server.h"
00023 #include "protocol.h"
00024 #include "data.h"
00025 #include "endian.h"
00026 #include "debug.h"
00027 #include "j_message.h"
00028 #include "protostructs.h"
00029 #include "record-internal.h"
00030 #include "error.h"
00031
00032 #include <unistd.h>
00033 #include <fcntl.h>
00034 #include <sys/types.h>
00035 #include <sys/socket.h>
00036 #include <netinet/in.h>
00037 #include <arpa/inet.h>
00038 #include <netdb.h>
00039 #include <string.h>
00040 #include <errno.h>
00041
00042 #include <sstream>
00043 #include <algorithm>
00044
00045 using namespace std;
00046
00047 namespace Barry { namespace JDWP {
00048
00049 static void * acceptThread(void *data);
00050
00051
00052 JDWServer::JDWServer(Barry::Mode::JVMDebug &device,
00053 const char *address, int port)
00054 : jvmdebug(&device)
00055 , acceptfd(-1)
00056 , sockfd(-1)
00057 , address(address)
00058 , port(port)
00059 , loop(false)
00060 , targetrunning(false)
00061 , printConsoleMessage(0)
00062 {
00063 SearchDebugFile(debugFileList);
00064 }
00065
00066
00067 JDWServer::~JDWServer()
00068 {
00069 Stop();
00070 }
00071
00072
00073 void JDWServer::SetPasswordDevice(string password)
00074 {
00075 this->password = password;
00076 }
00077
00078
00079 void JDWServer::SetConsoleCallback(ConsoleCallbackType callback)
00080 {
00081 printConsoleMessage = callback;
00082 }
00083
00084 static const char* h_strerror(int code)
00085 {
00086
00087 switch( code )
00088 {
00089 case HOST_NOT_FOUND:
00090 return "HOST_NOT_FOUND: The specified host is unknown";
00091
00092 case NO_ADDRESS:
00093 return "NO_ADDRESS: The requested name is valid but does not have an IP address";
00094
00095 case NO_RECOVERY:
00096 return "NO_RECOVERY: A non-recoverable name server error occurred";
00097
00098 case TRY_AGAIN:
00099 return "TRY_AGAIN: A temporary error occurred on an authoritative name server. Try again later.";
00100
00101 default:
00102 return "Unknown network error code";
00103 }
00104 }
00105
00106 bool JDWServer::Start()
00107 {
00108 int rc;
00109
00110 struct hostent *hp;
00111 struct sockaddr_in sad;
00112
00113
00114 memset((char *) &sad, '\0', sizeof(struct sockaddr_in));
00115
00116 if (!address.size())
00117 sad.sin_addr.s_addr = INADDR_ANY;
00118 else {
00119 sad.sin_addr.s_addr = inet_addr(address.c_str());
00120
00121 if (sad.sin_addr.s_addr == INADDR_NONE) {
00122 hp = gethostbyname(address.c_str());
00123
00124 if (hp == NULL) {
00125 std::ostringstream oss;
00126 oss << "JDWServer::Start: " << h_errno << h_strerror(h_errno);
00127 throw Barry::Error(oss.str());
00128 }
00129
00130 memcpy((char*) &sad.sin_addr, (char*) hp->h_addr, (size_t) hp->h_length);
00131 }
00132 }
00133
00134 sad.sin_family = AF_INET;
00135 sad.sin_port = htons((short) (port & 0xFFFF));
00136
00137
00138 sockfd = socket(sad.sin_family, SOCK_STREAM, 0);
00139
00140 if (sockfd < 0) {
00141 throw Barry::ErrnoError("JDWServer::Start: Cannot open socket.", errno);
00142 }
00143
00144
00145 rc = bind(sockfd, (struct sockaddr *) &sad, sizeof(sad));
00146
00147 if (rc < 0) {
00148 int code = errno;
00149
00150 close(sockfd);
00151 sockfd = -1;
00152
00153 throw Barry::ErrnoError("JDWServer::Start: Cannot bind socket", code);
00154 }
00155
00156
00157 if (listen(sockfd, SOMAXCONN) < 0) {
00158 int code = errno;
00159
00160 close(sockfd);
00161 sockfd = -1;
00162
00163 throw Barry::ErrnoError("JDWServer::Start: Cannot listen on socket", code);
00164 }
00165
00166 handler.reset(new Thread(sockfd, acceptThread, (void*) this));
00167
00168 return true;
00169 }
00170
00171
00172 static void * acceptThread(void *data)
00173 {
00174 JDWServer *s;
00175
00176 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00177
00178 s = (JDWServer *) data;
00179
00180 while (1) {
00181 if( s->AcceptConnection() &&
00182 s->AttachToDevice() &&
00183 s->InitVisibleClassList() &&
00184 s->Hello() )
00185 {
00186 s->Run();
00187 s->DetachFromDevice();
00188 }
00189 }
00190
00191 return NULL;
00192 }
00193
00194
00195
00196 bool JDWServer::AcceptConnection()
00197 {
00198 struct sockaddr_in addr;
00199 struct sockaddr *sa = (struct sockaddr*) &addr;
00200 socklen_t addrlen = sizeof(addr);
00201
00202 acceptfd = accept(sockfd, sa, &addrlen);
00203 if( acceptfd < 0 )
00204 return false;
00205
00206 fcntl(acceptfd, F_SETFL, O_NONBLOCK);
00207 return true;
00208 }
00209
00210
00211 bool JDWServer::AttachToDevice()
00212 {
00213 targetrunning = false;
00214
00215 jvmdebug->Open(password.c_str());
00216 jvmdebug->Attach();
00217
00218 jvmdebug->Unknown01();
00219 jvmdebug->Unknown02();
00220 jvmdebug->Unknown03();
00221 jvmdebug->Unknown04();
00222 jvmdebug->Unknown05();
00223
00224 jvmdebug->GetModulesList(modulesList);
00225 dout(modulesList);
00226
00227
00228 JVMModulesList::const_iterator b = modulesList.begin();
00229 for ( ; b != modulesList.end(); b++) {
00230 JDG::CodInfo codInfo;
00231
00232 const JVMModulesEntry &entry = *b;
00233
00234 bool ret = LoadDebugInfo(debugFileList, entry.UniqueID, entry.Name, codInfo);
00235
00236 if (ret == true) {
00237 appList[entry.UniqueID].Load(codInfo);
00238 }
00239 else {
00240 dout("No debug information found for '" << entry.Name);
00241 dout("' (" << hex << setfill('0') << setw(8) << entry.UniqueID << ")." << endl)
00242 }
00243 }
00244
00245 return true;
00246 }
00247
00248
00249 void JDWServer::DetachFromDevice()
00250 {
00251 jvmdebug->Detach();
00252 jvmdebug->Close();
00253 }
00254
00255
00256 #define JDWP_HELLO_STRING "JDWP-Handshake"
00257
00258
00259
00260 bool JDWServer::Hello()
00261 {
00262 bool ret;
00263
00264 Barry::Data response;
00265
00266 const size_t len = strlen(JDWP_HELLO_STRING);
00267
00268 JDWMessage msg(acceptfd);
00269
00270 do {
00271 ret = msg.Receive(response);
00272 }
00273 while (!ret);
00274
00275 size_t size = response.GetSize();
00276 char *str = (char *) response.GetBuffer();
00277
00278 if (size != len)
00279 return false;
00280
00281 if (!strncmp(str, JDWP_HELLO_STRING, len)) {
00282 Data command(JDWP_HELLO_STRING, len);
00283
00284 msg.Send(command);
00285
00286 return true;
00287 }
00288
00289 return false;
00290 }
00291
00292
00293 void JDWServer::Run()
00294 {
00295 string str;
00296 JDWMessage msg(acceptfd);
00297
00298 Barry::Data command;
00299
00300 MAKE_JDWPPACKET(rpack, command);
00301
00302 loop = true;
00303
00304 while (loop) {
00305 if (targetrunning) {
00306
00307 int value = jvmdebug->GetConsoleMessage(str);
00308
00309 if (value < 0) {
00310 bool ret;
00311 int status;
00312
00313 ret = jvmdebug->GetStatus(status);
00314
00315 while (!ret) {
00316
00317 msg.Receive(command);
00318
00319 if (command.GetSize() > 0) {
00320
00321 rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData();
00322
00323 if (command.GetSize() != be_btohl(rpack->length)) {
00324 dout("Packet size error !!!" << endl);
00325
00326
00327
00328 continue;
00329 }
00330
00331 CommandsetProcess(command);
00332
00333 break;
00334 }
00335 else
00336 ret = jvmdebug->WaitStatus(status);
00337 }
00338 }
00339 else {
00340 if (printConsoleMessage != NULL)
00341 printConsoleMessage(str);
00342 }
00343 }
00344 else {
00345
00346 msg.Receive(command);
00347
00348 if (command.GetSize() > 0) {
00349
00350 rpack = (const Barry::Protocol::JDWP::Packet *) command.GetData();
00351
00352 if (command.GetSize() != be_btohl(rpack->length)) {
00353 dout("Packet size error !!!" << endl);
00354
00355
00356
00357 continue;
00358 }
00359
00360 CommandsetProcess(command);
00361 }
00362
00363 usleep(50);
00364 }
00365 }
00366 }
00367
00368
00369 bool JDWServer::Stop()
00370 {
00371 if( handler.get() ) {
00372 handler->Dispose();
00373 handler.reset();
00374 }
00375
00376 if( sockfd >= 0 ) {
00377 close(sockfd);
00378 sockfd = -1;
00379 }
00380
00381 if( acceptfd >= 0 ) {
00382 close(acceptfd);
00383 acceptfd = -1;
00384 }
00385
00386 return true;
00387 }
00388
00389
00390 bool JDWServer::InitVisibleClassList()
00391 {
00392 int index;
00393
00394
00395
00396
00397 JDG::ClassEntry e;
00398 visibleClassList.push_back(e);
00399
00400
00401 index = 1;
00402 JDWAppList::iterator it;
00403
00404 for (it = appList.begin(); it != appList.end(); it++) {
00405 JDWAppInfo &appInfo = it->second;
00406 JDG::ClassList &list = appInfo.classList;
00407
00408 JDG::ClassList::iterator b;
00409
00410 for (b = list.begin(); b != list.end(); b++) {
00411
00412
00413
00414 if (b->id == 0xffffffff) {
00415 b->index = -1;
00416
00417 continue;
00418 }
00419
00420 b->index = index;
00421
00422 visibleClassList.push_back(*b);
00423
00424 index++;
00425 }
00426 }
00427
00428 visibleClassList.CreateDefaultEntries();
00429
00430 return true;
00431 }
00432
00433
00434 void JDWServer::CommandsetProcess(Data &cmd)
00435 {
00436 MAKE_JDWPPACKET(rpack, cmd);
00437
00438 switch (rpack->u.command.commandset) {
00439 case JDWP_CMDSET_VIRTUALMACHINE:
00440 CommandsetVirtualMachineProcess(cmd);
00441 break;
00442
00443 case JDWP_CMDSET_REFERECENTYPE:
00444 break;
00445
00446 case JDWP_CMDSET_CLASSTYPE:
00447 break;
00448
00449 case JDWP_CMDSET_ARRAYTYPE:
00450 break;
00451
00452 case JDWP_CMDSET_INTERFACETYPE:
00453 break;
00454
00455 case JDWP_CMDSET_METHOD:
00456 break;
00457
00458 case JDWP_CMDSET_FIELD:
00459 break;
00460
00461 case JDWP_CMDSET_OBJECTREFERENCE:
00462 break;
00463
00464 case JDWP_CMDSET_STRINGREFERENCE:
00465 break;
00466
00467 case JDWP_CMDSET_THREADREFERENCE:
00468 break;
00469
00470 case JDWP_CMDSET_THREADGROUPREFERENCE:
00471 break;
00472
00473 case JDWP_CMDSET_ARRAYREFERENCE:
00474 break;
00475
00476 case JDWP_CMDSET_CLASSLOADERREFERENCE:
00477 break;
00478
00479 case JDWP_CMDSET_EVENTREQUEST:
00480 CommandsetEventRequestProcess(cmd);
00481 break;
00482
00483 case JDWP_CMDSET_STACKFRAME:
00484 break;
00485
00486 case JDWP_CMDSET_CLASSOBJECTREFERENCE:
00487 break;
00488
00489 case JDWP_CMDSET_EVENT:
00490 break;
00491
00492 default:
00493
00494 dout("Commandset unknown !!!" << endl);
00495 }
00496 }
00497
00498
00499 void JDWServer::CommandsetVirtualMachineProcess(Data &cmd)
00500 {
00501 MAKE_JDWPPACKET(rpack, cmd);
00502
00503 switch (rpack->u.command.command) {
00504 case JDWP_CMD_VERSION:
00505 CommandVersion(cmd);
00506 break;
00507
00508 case JDWP_CMD_ALLCLASSES:
00509 CommandAllClasses(cmd);
00510 break;
00511
00512 case JDWP_CMD_ALLTHREADS:
00513 CommandAllThreads(cmd);
00514 break;
00515
00516 case JDWP_CMD_DISPOSE:
00517 loop = false;
00518 targetrunning = false;
00519 close(acceptfd);
00520 acceptfd = -1;
00521 break;
00522
00523 case JDWP_CMD_IDSIZES:
00524 CommandIdSizes(cmd);
00525 break;
00526
00527 case JDWP_CMD_SUSPEND:
00528 CommandSuspend(cmd);
00529 targetrunning = false;
00530 break;
00531
00532 case JDWP_CMD_RESUME:
00533 CommandResume(cmd);
00534 targetrunning = true;
00535 break;
00536
00537 case JDWP_CMD_CLASSPATHS:
00538 CommandClassPaths(cmd);
00539 break;
00540 }
00541 }
00542
00543
00544 void JDWServer::CommandsetEventRequestProcess(Data &cmd)
00545 {
00546 MAKE_JDWPPACKET(rpack, cmd);
00547
00548 switch (rpack->u.command.command) {
00549 case JDWP_CMD_SET:
00550 CommandSet(cmd);
00551 break;
00552 }
00553 }
00554
00555
00556 void JDWServer::CommandVersion(Data &cmd)
00557 {
00558 JDWMessage msg(acceptfd);
00559
00560
00561 Data response;
00562
00563 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00564
00565 AddJDWString(response, offset, string("RIM JVM"));
00566 AddJDWInt(response, offset, be_htobl(1));
00567 AddJDWInt(response, offset, be_htobl(4));
00568 AddJDWString(response, offset, string("1.4"));
00569 AddJDWString(response, offset, string("RIM JVM"));
00570
00571 response.ReleaseBuffer(offset);
00572
00573
00574 size_t total_size = response.GetSize();
00575
00576
00577 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00578 Barry::Protocol::JDWP::Packet &packet = *cpack;
00579
00580
00581 MAKE_JDWPPACKET(rpack, cmd);
00582
00583 packet.length = be_htobl(total_size);
00584 packet.id = rpack->id;
00585 packet.flags = 0x80;
00586 packet.u.response.errorcode = be_htobs(0);
00587
00588 response.ReleaseBuffer(total_size);
00589 msg.Send(response);
00590 }
00591
00592
00593 void JDWServer::CommandAllClasses(Data &cmd)
00594 {
00595 size_t i;
00596 int size;
00597
00598 JDWMessage msg(acceptfd);
00599
00600
00601 Data response;
00602
00603 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00604
00605
00606 size = visibleClassList.size() - 1;
00607
00608 AddJDWInt(response, offset, be_htobl(size));
00609
00610
00611 for (i=1; i<visibleClassList.size(); i++) {
00612 string str = visibleClassList[i].GetFullClassName();
00613
00614 str = "L" + str + ";";
00615 replace_if(str.begin(), str.end(), bind2nd(equal_to<char>(),'.'), '/');
00616
00617 AddJDWByte(response, offset, 0x01);
00618 AddJDWInt(response, offset, i);
00619 AddJDWString(response, offset, str);
00620 AddJDWInt(response, offset, be_htobl(0x04));
00621 }
00622
00623 response.ReleaseBuffer(offset);
00624
00625
00626 size_t total_size = response.GetSize();
00627
00628
00629 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00630 Barry::Protocol::JDWP::Packet &packet = *cpack;
00631
00632
00633 MAKE_JDWPPACKET(rpack, cmd);
00634
00635 packet.length = be_htobl(total_size);
00636 packet.id = rpack->id;
00637 packet.flags = 0x80;
00638 packet.u.response.errorcode = be_htobs(0);
00639
00640 response.ReleaseBuffer(total_size);
00641 msg.Send(response);
00642 }
00643
00644
00645 void JDWServer::CommandAllThreads(Data &cmd)
00646 {
00647 JDWMessage msg(acceptfd);
00648
00649
00650 JVMThreadsList list;
00651 jvmdebug->GetThreadsList(list);
00652 dout(list);
00653
00654
00655 Data response;
00656
00657 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00658
00659
00660 AddJDWInt(response, offset, be_htobl(list.size()));
00661
00662
00663 JVMThreadsList::const_iterator b = list.begin();
00664 for( ; b != list.end(); b++ ) {
00665 const JVMThreadsEntry &entry = *b;
00666
00667 AddJDWInt(response, offset, be_htobl(entry.Id));
00668 }
00669
00670 response.ReleaseBuffer(offset);
00671
00672
00673 size_t total_size = response.GetSize();
00674
00675
00676 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00677 Barry::Protocol::JDWP::Packet &packet = *cpack;
00678
00679
00680 MAKE_JDWPPACKET(rpack, cmd);
00681
00682 packet.length = be_htobl(total_size);
00683 packet.id = rpack->id;
00684 packet.flags = 0x80;
00685 packet.u.response.errorcode = be_htobs(0);
00686
00687 response.ReleaseBuffer(total_size);
00688 msg.Send(response);
00689 }
00690
00691
00692 void JDWServer::CommandIdSizes(Data &cmd)
00693 {
00694 JDWMessage msg(acceptfd);
00695
00696 MAKE_JDWPPACKET(rpack, cmd);
00697
00698 size_t size;
00699
00700 Barry::Protocol::JDWP::Packet packet;
00701
00702 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE
00703 + JDWP_PACKETVIRTUALMACHINEIDSIZES_DATA_SIZE;
00704
00705 packet.length = be_htobl(size);
00706 packet.id = rpack->id;
00707 packet.flags = 0x80;
00708 packet.u.response.errorcode = be_htobs(0);
00709 packet.u.response.u.virtualMachine.u.IDSizes.fieldIDSize = be_htobl(0x04);
00710 packet.u.response.u.virtualMachine.u.IDSizes.methodIDSize = be_htobl(0x04);
00711 packet.u.response.u.virtualMachine.u.IDSizes.objectIDSize = be_htobl(0x04);
00712 packet.u.response.u.virtualMachine.u.IDSizes.referenceTypeIDSize = be_htobl(0x04);
00713 packet.u.response.u.virtualMachine.u.IDSizes.frameIDSize = be_htobl(0x04);
00714
00715 Data response(&packet, size);
00716
00717 msg.Send(response);
00718 }
00719
00720
00721 void JDWServer::CommandSuspend(Data &cmd)
00722 {
00723 JDWMessage msg(acceptfd);
00724
00725
00726
00727 jvmdebug->Stop();
00728
00729
00730 MAKE_JDWPPACKET(rpack, cmd);
00731
00732 size_t size;
00733
00734 Barry::Protocol::JDWP::Packet packet;
00735
00736 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00737
00738 packet.length = be_htobl(size);
00739 packet.id = rpack->id;
00740 packet.flags = 0x80;
00741 packet.u.response.errorcode = be_htobs(0);
00742
00743 Data response(&packet, size);
00744
00745 msg.Send(response);
00746 }
00747
00748
00749 void JDWServer::CommandResume(Data &cmd)
00750 {
00751 JDWMessage msg(acceptfd);
00752
00753
00754
00755 jvmdebug->Unknown06();
00756 jvmdebug->Unknown07();
00757 jvmdebug->Unknown08();
00758 jvmdebug->Unknown09();
00759 jvmdebug->Unknown10();
00760 jvmdebug->Go();
00761
00762
00763 MAKE_JDWPPACKET(rpack, cmd);
00764
00765 size_t size;
00766
00767 Barry::Protocol::JDWP::Packet packet;
00768
00769 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00770
00771 packet.length = be_htobl(size);
00772 packet.id = rpack->id;
00773 packet.flags = 0x80;
00774 packet.u.response.errorcode = be_htobs(0);
00775
00776 Data response(&packet, size);
00777
00778 msg.Send(response);
00779 }
00780
00781
00782 void JDWServer::CommandClassPaths(Data &cmd)
00783 {
00784 JDWMessage msg(acceptfd);
00785
00786
00787 Data response;
00788
00789 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
00790
00791 AddJDWString(response, offset, string(""));
00792 AddJDWInt(response, offset, be_htobl(0));
00793 AddJDWInt(response, offset, be_htobl(0));
00794
00795 response.ReleaseBuffer(offset);
00796
00797
00798 size_t total_size = response.GetSize();
00799
00800
00801 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
00802 Barry::Protocol::JDWP::Packet &packet = *cpack;
00803
00804
00805 MAKE_JDWPPACKET(rpack, cmd);
00806
00807 packet.length = be_htobl(total_size);
00808 packet.id = rpack->id;
00809 packet.flags = 0x80;
00810 packet.u.response.errorcode = be_htobs(0);
00811
00812 response.ReleaseBuffer(total_size);
00813 msg.Send(response);
00814 }
00815
00816
00817
00818 void JDWServer::CommandSet(Data &cmd)
00819 {
00820 static int value = 2;
00821
00822 JDWMessage msg(acceptfd);
00823
00824 MAKE_JDWPPACKET(rpack, cmd);
00825
00826 size_t size;
00827
00828 Barry::Protocol::JDWP::Packet packet;
00829
00830 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE + sizeof(uint32_t);
00831
00832 packet.length = be_htobl(size);
00833 packet.id = rpack->id;
00834 packet.flags = 0x80;
00835 packet.u.response.errorcode = be_htobs(0);
00836 packet.u.response.u.value = be_htobl(value);
00837
00838 Data response(&packet, size);
00839
00840 msg.Send(response);
00841
00842 value++;
00843 }
00844
00845
00846 }}
00847