• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "jdwp.h"
16 #include <sys/eventfd.h>
17 #include <thread>
18 
19 namespace Hdc {
HdcJdwp(uv_loop_t * loopIn)20 HdcJdwp::HdcJdwp(uv_loop_t *loopIn)
21 {
22     listenPipe.data = this;
23     loop = loopIn;
24     refCount = 0;
25     stop = false;
26     awakenPollFd = -1;
27     uv_rwlock_init(&lockMapContext);
28     uv_rwlock_init(&lockJdwpTrack);
29     awakenPollFd = -1;
30     stop = false;
31 }
32 
~HdcJdwp()33 HdcJdwp::~HdcJdwp()
34 {
35     if (awakenPollFd >= 0) {
36         close(awakenPollFd);
37         awakenPollFd = -1;
38     }
39     uv_rwlock_destroy(&lockMapContext);
40     uv_rwlock_destroy(&lockJdwpTrack);
41 }
42 
ReadyForRelease()43 bool HdcJdwp::ReadyForRelease()
44 {
45     return refCount == 0;
46 }
47 
Stop()48 void HdcJdwp::Stop()
49 {
50     stop = true;
51     WakePollThread();
52     auto funcListenPipeClose = [](uv_handle_t *handle) -> void {
53         HdcJdwp *thisClass = (HdcJdwp *)handle->data;
54         --thisClass->refCount;
55     };
56     Base::TryCloseHandle((const uv_handle_t *)&listenPipe, funcListenPipeClose);
57     freeContextMutex.lock();
58     for (auto &&obj : mapCtxJdwp) {
59         HCtxJdwp v = obj.second;
60         FreeContext(v);
61     }
62     AdminContext(OP_CLEAR, 0, nullptr);
63     freeContextMutex.unlock();
64 }
65 
MallocContext()66 void *HdcJdwp::MallocContext()
67 {
68     HCtxJdwp ctx = nullptr;
69     if ((ctx = new ContextJdwp()) == nullptr) {
70         return nullptr;
71     }
72     ctx->thisClass = this;
73     ctx->pipe.data = ctx;
74     ++refCount;
75     return ctx;
76 }
77 
78 // Single thread, two parameters can be used
FreeContext(HCtxJdwp ctx)79 void HdcJdwp::FreeContext(HCtxJdwp ctx)
80 {
81     if (ctx->finish) {
82         return;
83     }
84     ctx->finish = true;
85     WRITE_LOG(LOG_INFO, "FreeContext for targetPID :%d", ctx->pid);
86     Base::TryCloseHandle((const uv_handle_t *)&ctx->pipe);
87     AdminContext(OP_REMOVE, ctx->pid, nullptr);
88     auto funcReqClose = [](uv_idle_t *handle) -> void {
89         HCtxJdwp ctx = (HCtxJdwp)handle->data;
90         --ctx->thisClass->refCount;
91         Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseIdleCallback);
92         delete ctx;
93     };
94     Base::IdleUvTask(loop, ctx, funcReqClose);
95 }
96 
RemoveFdFromPollList(uint32_t pid)97 void HdcJdwp::RemoveFdFromPollList(uint32_t pid)
98 {
99     for (auto &&pair : pollNodeMap) {
100         if (pair.second.ppid == pid) {
101             WRITE_LOG(LOG_INFO, "RemoveFdFromPollList for pid:%d.", pid);
102             pollNodeMap.erase(pair.second.pollfd.fd);
103             break;
104         }
105     }
106 }
107 
ReadStream(uv_stream_t * pipe,ssize_t nread,const uv_buf_t * buf)108 void HdcJdwp::ReadStream(uv_stream_t *pipe, ssize_t nread, const uv_buf_t *buf)
109 {
110     bool ret = true;
111     if (nread == UV_ENOBUFS) {  // It is definite enough, usually only 4 bytes
112         ret = false;
113         WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream IOBuf max");
114     } else if (nread == 0) {
115         return;
116 #ifdef JS_JDWP_CONNECT
117     } else if (nread < JS_PKG_MIN_SIZE || nread > JS_PKG_MX_SIZE) { // valid Js package size
118 #else
119     } else if (nread < 0 || nread != 4) {  // 4 : 4 bytes
120 #endif  // JS_JDWP_CONNECT
121         ret = false;
122         WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream invalid package nread:%d.", nread);
123     }
124 
125     HCtxJdwp ctxJdwp = static_cast<HCtxJdwp>(pipe->data);
126     HdcJdwp *thisClass = static_cast<HdcJdwp *>(ctxJdwp->thisClass);
127     if (ret) {
128         uint32_t pid = 0;
129         char *p = ctxJdwp->buf;
130         if (nread == sizeof(uint32_t)) {  // Java: pid
131             pid = atoi(p);
132         } else {  // JS:pid PkgName
133 #ifdef JS_JDWP_CONNECT
134             struct JsMsgHeader *jsMsg = reinterpret_cast<struct JsMsgHeader *>(p);
135             if (jsMsg->msgLen == nread) {
136                 pid = jsMsg->pid;
137                 string pkgName = string((char *)p + sizeof(JsMsgHeader), jsMsg->msgLen - sizeof(JsMsgHeader));
138                 ctxJdwp->pkgName = pkgName;
139             } else {
140                 ret = false;
141                 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream invalid js package size %d:%d.", jsMsg->msgLen, nread);
142             }
143 #endif  // JS_JDWP_CONNECT
144         }
145         if (pid > 0) {
146             ctxJdwp->pid = pid;
147 #ifdef JS_JDWP_CONNECT
148             WRITE_LOG(LOG_DEBUG, "JDWP accept pid:%d-pkg:%s", pid, ctxJdwp->pkgName.c_str());
149 #else
150             WRITE_LOG(LOG_DEBUG, "JDWP accept pid:%d", pid);
151 #endif  // JS_JDWP_CONNECT
152             thisClass->AdminContext(OP_ADD, pid, ctxJdwp);
153             ret = true;
154             int fd = -1;
155             if (uv_fileno(reinterpret_cast<uv_handle_t *>(&(ctxJdwp->pipe)), &fd) < 0) {
156                 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream uv_fileno fail.");
157             } else {
158                 thisClass->freeContextMutex.lock();
159                 thisClass->pollNodeMap.emplace(fd, PollNode(fd, pid));
160                 thisClass->freeContextMutex.unlock();
161                 thisClass->WakePollThread();
162             }
163         }
164     }
165     Base::ZeroArray(ctxJdwp->buf);
166     if (!ret) {
167         WRITE_LOG(LOG_INFO, "ReadStream proc:%d err, free it.", ctxJdwp->pid);
168         thisClass->freeContextMutex.lock();
169         thisClass->FreeContext(ctxJdwp);
170         thisClass->freeContextMutex.unlock();
171     }
172 }
173 
174 #ifdef JS_JDWP_CONNECT
GetProcessListExtendPkgName()175 string HdcJdwp::GetProcessListExtendPkgName()
176 {
177     string ret;
178     uv_rwlock_rdlock(&lockMapContext);
179     for (auto &&v : mapCtxJdwp) {
180         HCtxJdwp hj = v.second;
181         ret += std::to_string(v.first) + " " + hj->pkgName + "\n";
182     }
183     uv_rwlock_rdunlock(&lockMapContext);
184     return ret;
185 }
186 #endif  // JS_JDWP_CONNECT
187 
AcceptClient(uv_stream_t * server,int status)188 void HdcJdwp::AcceptClient(uv_stream_t *server, int status)
189 {
190     uv_pipe_t *listenPipe = (uv_pipe_t *)server;
191     HdcJdwp *thisClass = (HdcJdwp *)listenPipe->data;
192     HCtxJdwp ctxJdwp = (HCtxJdwp)thisClass->MallocContext();
193     if (!ctxJdwp) {
194         return;
195     }
196     uv_pipe_init(thisClass->loop, &ctxJdwp->pipe, 1);
197     if (uv_accept(server, (uv_stream_t *)&ctxJdwp->pipe) < 0) {
198         WRITE_LOG(LOG_DEBUG, "uv_accept failed");
199         thisClass->freeContextMutex.lock();
200         thisClass->FreeContext(ctxJdwp);
201         thisClass->freeContextMutex.unlock();
202         return;
203     }
204     auto funAlloc = [](uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf) -> void {
205         HCtxJdwp ctxJdwp = (HCtxJdwp)handle->data;
206         buf->base = (char *)ctxJdwp->buf;
207         buf->len = sizeof(ctxJdwp->buf);
208     };
209     uv_read_start((uv_stream_t *)&ctxJdwp->pipe, funAlloc, ReadStream);
210 }
211 
212 // Test bash connnet(UNIX-domain sockets):nc -U path/jdwp-control < hexpid.file
213 // Test uv connect(pipe): 'uv_pipe_connect'
JdwpListen()214 bool HdcJdwp::JdwpListen()
215 {
216 #ifdef HDC_PCDEBUG
217     // if test, canbe enable
218     return true;
219     const char jdwpCtrlName[] = { 'j', 'd', 'w', 'p', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 };
220     unlink(jdwpCtrlName);
221 #else
222     const char jdwpCtrlName[] = { '\0', 'j', 'd', 'w', 'p', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 };
223 #endif
224     const int DEFAULT_BACKLOG = 4;
225     bool ret = false;
226     while (true) {
227         uv_pipe_init(loop, &listenPipe, 0);
228         listenPipe.data = this;
229         if ((uv_pipe_bind(&listenPipe, jdwpCtrlName))) {
230             constexpr int bufSize = 1024;
231             char buf[bufSize] = { 0 };
232             strerror_r(errno, buf, bufSize);
233             WRITE_LOG(LOG_WARN, "Bind error : %d: %s", errno, buf);
234             return 1;
235         }
236         if (uv_listen((uv_stream_t *)&listenPipe, DEFAULT_BACKLOG, AcceptClient)) {
237             break;
238         }
239         ++refCount;
240         ret = true;
241         break;
242     }
243     // listenPipe close by stop
244     return ret;
245 }
246 
247 // Working in the main thread, but will be accessed by each session thread, so we need to set thread lock
AdminContext(const uint8_t op,const uint32_t pid,HCtxJdwp ctxJdwp)248 void *HdcJdwp::AdminContext(const uint8_t op, const uint32_t pid, HCtxJdwp ctxJdwp)
249 {
250     HCtxJdwp hRet = nullptr;
251     switch (op) {
252         case OP_ADD: {
253             uv_rwlock_wrlock(&lockMapContext);
254             mapCtxJdwp[pid] = ctxJdwp;
255             uv_rwlock_wrunlock(&lockMapContext);
256             break;
257         }
258         case OP_REMOVE:
259             uv_rwlock_wrlock(&lockMapContext);
260             mapCtxJdwp.erase(pid);
261             RemoveFdFromPollList(pid);
262             uv_rwlock_wrunlock(&lockMapContext);
263             break;
264         case OP_QUERY: {
265             uv_rwlock_rdlock(&lockMapContext);
266             if (mapCtxJdwp.count(pid)) {
267                 hRet = mapCtxJdwp[pid];
268             }
269             uv_rwlock_rdunlock(&lockMapContext);
270             break;
271         }
272         case OP_CLEAR: {
273             uv_rwlock_wrlock(&lockMapContext);
274             mapCtxJdwp.clear();
275             pollNodeMap.clear();
276             uv_rwlock_wrunlock(&lockMapContext);
277             break;
278         }
279         default:
280             break;
281     }
282     if (op == OP_ADD || op == OP_REMOVE || op == OP_CLEAR) {
283         uv_rwlock_wrlock(&lockJdwpTrack);
284         ProcessListUpdated();
285         uv_rwlock_wrunlock(&lockJdwpTrack);
286     }
287     return hRet;
288 }
289 
290 // work on main thread
SendCallbackJdwpNewFD(uv_write_t * req,int status)291 void HdcJdwp::SendCallbackJdwpNewFD(uv_write_t *req, int status)
292 {
293     // It usually works successful, not notify session work
294     HCtxJdwp ctx = (HCtxJdwp)req->data;
295     if (status >= 0) {
296         WRITE_LOG(LOG_DEBUG, "SendCallbackJdwpNewFD successful %d, active jdwp forward", ctx->pid);
297     } else {
298         WRITE_LOG(LOG_WARN, "SendCallbackJdwpNewFD failed %d", ctx->pid);
299     }
300     // close my process's fd
301     Base::TryCloseHandle((const uv_handle_t *)&ctx->jvmTCP);
302     delete req;
303     --ctx->thisClass->refCount;
304 }
305 
306 // Each session calls the interface through the main thread message queue, which cannot be called directly across
307 // threads
308 // work on main thread
SendJdwpNewFD(uint32_t targetPID,int fd)309 bool HdcJdwp::SendJdwpNewFD(uint32_t targetPID, int fd)
310 {
311     bool ret = false;
312     while (true) {
313         HCtxJdwp ctx = (HCtxJdwp)AdminContext(OP_QUERY, targetPID, nullptr);
314         if (!ctx) {
315             break;
316         }
317         ctx->dummy = (uint8_t)'!';
318         if (uv_tcp_init(loop, &ctx->jvmTCP)) {
319             break;
320         }
321         if (uv_tcp_open(&ctx->jvmTCP, fd)) {
322             break;
323         }
324         // transfer fd to jvm
325         // clang-format off
326         if (Base::SendToStreamEx((uv_stream_t *)&ctx->pipe, (uint8_t *)&ctx->dummy, 1, (uv_stream_t *)&ctx->jvmTCP,
327             (void *)SendCallbackJdwpNewFD, (const void *)ctx) < 0) {
328             break;
329         }
330         // clang-format on
331         ++refCount;
332         ret = true;
333         WRITE_LOG(LOG_DEBUG, "SendJdwpNewFD successful targetPID:%d fd%d", targetPID, fd);
334         break;
335     }
336     return ret;
337 }
338 
339 // cross thread call begin
CheckPIDExist(uint32_t targetPID)340 bool HdcJdwp::CheckPIDExist(uint32_t targetPID)
341 {
342     HCtxJdwp ctx = (HCtxJdwp)AdminContext(OP_QUERY, targetPID, nullptr);
343     return ctx != nullptr;
344 }
345 
GetProcessList()346 string HdcJdwp::GetProcessList()
347 {
348     string ret;
349     uv_rwlock_rdlock(&lockMapContext);
350     for (auto &&v : mapCtxJdwp) {
351         ret += std::to_string(v.first) + "\n";
352     }
353     uv_rwlock_rdunlock(&lockMapContext);
354     return ret;
355 }
356 // cross thread call finish
357 
JdwpProcessListMsg(char * buffer,size_t bufferlen)358 size_t HdcJdwp::JdwpProcessListMsg(char *buffer, size_t bufferlen)
359 {
360     // Message is length-prefixed with 4 hex digits in ASCII.
361     static constexpr size_t headerLen = 5;
362     char head[headerLen + 2];
363 #ifdef JS_JDWP_CONNECT
364     string result = GetProcessListExtendPkgName();
365 #else
366     string result = GetProcessList();
367 #endif // JS_JDWP_CONNECT
368 
369     size_t len = result.length();
370     if (bufferlen < (len + headerLen)) {
371         WRITE_LOG(LOG_WARN, "truncating JDWP process list (max len = %zu) ", bufferlen);
372         len = bufferlen;
373     }
374     if (snprintf_s(head, sizeof head, sizeof head - 1, "%04zx\n", len) < 0) {
375         WRITE_LOG(LOG_WARN, " JdwpProcessListMsg head fail.");
376         return 0;
377     }
378     if (memcpy_s(buffer, bufferlen, head, headerLen) != EOK) {
379         WRITE_LOG(LOG_WARN, " JdwpProcessListMsg get head fail.");
380         return 0;
381     }
382     if (memcpy_s(buffer + headerLen, (bufferlen - headerLen), result.c_str(), len) != EOK) {
383         WRITE_LOG(LOG_WARN, " JdwpProcessListMsg get data  fail.");
384         return 0;
385     }
386     return len + headerLen;
387 }
388 
SendProcessList(HTaskInfo t,string data)389 void HdcJdwp::SendProcessList(HTaskInfo t, string data)
390 {
391     if (t == nullptr || data.size() == 0) {
392         WRITE_LOG(LOG_WARN, " SendProcessList, Nothing needs to be sent.");
393         return;
394     }
395     void *clsSession = t->ownerSessionClass;
396     HdcSessionBase *sessionBase = static_cast<HdcSessionBase *>(clsSession);
397     sessionBase->LogMsg(t->sessionId, t->channelId, MSG_OK, data.c_str());
398 }
399 
ProcessListUpdated(HTaskInfo task)400 void HdcJdwp::ProcessListUpdated(HTaskInfo task)
401 {
402     if (jdwpTrackers.size() <= 0) {
403         WRITE_LOG(LOG_DEBUG, "None jdwpTrackers.");
404         return;
405     }
406 #ifdef JS_JDWP_CONNECT
407     static constexpr uint32_t jpidTrackListSize = 1024 * 4;
408 #else
409     static constexpr uint32_t jpidTrackListSize = 1024;
410 #endif // JS_JDWP_CONNECT
411     std::string data;
412     data.resize(jpidTrackListSize);
413     size_t len = JdwpProcessListMsg(&data[0], data.size());
414     if (len <= 0) {
415         return;
416     }
417     data.resize(len);
418     if (task != nullptr) {
419         SendProcessList(task, data);
420     } else {
421         for (auto &t : jdwpTrackers) {
422             if (t == nullptr) {
423                 continue;
424             }
425             if (t->taskStop || t->taskFree || !t->taskClass) {  // The channel for the track-jpid has been stopped.
426                 jdwpTrackers.erase(remove(jdwpTrackers.begin(), jdwpTrackers.end(), t), jdwpTrackers.end());
427                 if (jdwpTrackers.size() <= 0) {
428                     return;
429                 }
430             } else {
431                 SendProcessList(t, data);
432             }
433         }
434     }
435 }
436 
CreateJdwpTracker(HTaskInfo taskInfo)437 bool HdcJdwp::CreateJdwpTracker(HTaskInfo taskInfo)
438 {
439     if (taskInfo == nullptr) {
440         return false;
441     }
442     uv_rwlock_wrlock(&lockJdwpTrack);
443     auto it = std::find(jdwpTrackers.begin(), jdwpTrackers.end(), taskInfo);
444     if (it == jdwpTrackers.end()) {
445         jdwpTrackers.push_back(taskInfo);
446     }
447     ProcessListUpdated(taskInfo);
448     uv_rwlock_wrunlock(&lockJdwpTrack);
449     return true;
450 }
451 
RemoveJdwpTracker(HTaskInfo taskInfo)452 void HdcJdwp::RemoveJdwpTracker(HTaskInfo taskInfo)
453 {
454     if (taskInfo == nullptr) {
455         return;
456     }
457     uv_rwlock_wrlock(&lockJdwpTrack);
458     auto it = std::find(jdwpTrackers.begin(), jdwpTrackers.end(), taskInfo);
459     if (it != jdwpTrackers.end()) {
460         WRITE_LOG(LOG_DEBUG, "RemoveJdwpTracker channelId:%d, taskType:%d.", taskInfo->channelId, taskInfo->taskType);
461         jdwpTrackers.erase(remove(jdwpTrackers.begin(), jdwpTrackers.end(), *it), jdwpTrackers.end());
462     }
463     uv_rwlock_wrunlock(&lockJdwpTrack);
464 }
465 
DrainAwakenPollThread() const466 void HdcJdwp::DrainAwakenPollThread() const
467 {
468     uint64_t value = 0;
469     ssize_t retVal = read(awakenPollFd, &value, sizeof(value));
470     if (retVal < 0) {
471         WRITE_LOG(LOG_FATAL, "DrainAwakenPollThread: Failed to read data from awaken pipe %d", retVal);
472     }
473 }
474 
WakePollThread()475 void HdcJdwp::WakePollThread()
476 {
477     if (awakenPollFd < 0) {
478         WRITE_LOG(LOG_DEBUG, "awakenPollFd: MUST initialized before notifying");
479         return;
480     }
481     static const uint64_t increment = 1;
482     ssize_t retVal = write(awakenPollFd, &increment, sizeof(increment));
483     if (retVal < 0) {
484         WRITE_LOG(LOG_FATAL, "WakePollThread: Failed to write data into awaken pipe %d", retVal);
485     }
486 }
487 
FdEventPollThread(void * args)488 void *HdcJdwp::FdEventPollThread(void *args)
489 {
490     auto thisClass = static_cast<HdcJdwp *>(args);
491     std::vector<struct pollfd> pollfds;
492     size_t size = 0;
493     while (!thisClass->stop) {
494         thisClass->freeContextMutex.lock();
495         if (size != thisClass->pollNodeMap.size() || thisClass->pollNodeMap.size() == 0) {
496             pollfds.clear();
497             struct pollfd pollFd;
498             for (const auto &pair : thisClass->pollNodeMap) {
499                 pollFd.fd = pair.second.pollfd.fd;
500                 pollFd.events = pair.second.pollfd.events;
501                 pollFd.revents = pair.second.pollfd.revents;
502                 pollfds.push_back(pollFd);
503             }
504             pollFd.fd = thisClass->awakenPollFd;
505             pollFd.events = POLLIN;
506             pollFd.revents = 0;
507             pollfds.push_back(pollFd);
508             size = pollfds.size();
509         }
510         thisClass->freeContextMutex.unlock();
511         poll(&pollfds[0], size, -1);
512         for (const auto &pollfdsing : pollfds) {
513             if (pollfdsing.revents & (POLLNVAL | POLLRDHUP | POLLHUP | POLLERR)) {  // POLLNVAL:fd not open
514                 thisClass->freeContextMutex.lock();
515                 auto it = thisClass->pollNodeMap.find(pollfdsing.fd);
516                 if (it != thisClass->pollNodeMap.end()) {
517                     uint32_t targetPID = it->second.ppid;
518                     HCtxJdwp ctx = static_cast<HCtxJdwp>(thisClass->AdminContext(OP_QUERY, targetPID, nullptr));
519                     if (ctx != nullptr) {
520                         thisClass->AdminContext(OP_REMOVE, targetPID, nullptr);
521                     }
522                 }
523                 thisClass->freeContextMutex.unlock();
524             } else if (pollfdsing.revents & POLLIN) {
525                 if (pollfdsing.fd == thisClass->awakenPollFd) {
526                     thisClass->DrainAwakenPollThread();
527                 }
528             }
529         }
530     }
531     return nullptr;
532 }
533 
CreateFdEventPoll()534 int HdcJdwp::CreateFdEventPoll()
535 {
536     pthread_t tid;
537     if (awakenPollFd >= 0) {
538         close(awakenPollFd);
539         awakenPollFd = -1;
540     }
541     awakenPollFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
542     if (awakenPollFd < 0) {
543         WRITE_LOG(LOG_FATAL, "CreateFdEventPoll : Failed to create awakenPollFd");
544         return ERR_GENERIC;
545     }
546     int tret = pthread_create(&tid, nullptr, FdEventPollThread, this);
547     if (tret != 0) {
548         WRITE_LOG(LOG_INFO, "FdEventPollThread create fail.");
549         return tret;
550     }
551     return RET_SUCCESS;
552 }
553 
554 // jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000
Initial()555 int HdcJdwp::Initial()
556 {
557     freeContextMutex.lock();
558     pollNodeMap.clear();
559     freeContextMutex.unlock();
560     if (!JdwpListen()) {
561         return ERR_MODULE_JDWP_FAILED;
562     }
563     if (CreateFdEventPoll() < 0) {
564         return ERR_MODULE_JDWP_FAILED;
565     }
566     return RET_SUCCESS;
567 }
568 }
569