OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [tools/] [ecostest/] [common/] [eCosTest.cpp] - Blame information for rev 790

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
2
// -------------------------------------------                              
3
// This file is part of the eCos host tools.                                
4
// Copyright (C) 1998, 1999, 2000, 2009 Free Software Foundation, Inc.            
5
//
6
// This program is free software; you can redistribute it and/or modify     
7
// it under the terms of the GNU General Public License as published by     
8
// the Free Software Foundation; either version 2 or (at your option) any   
9
// later version.                                                           
10
//
11
// This program is distributed in the hope that it will be useful, but      
12
// WITHOUT ANY WARRANTY; without even the implied warranty of               
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
14
// General Public License for more details.                                 
15
//
16
// You should have received a copy of the GNU General Public License        
17
// along with this program; if not, write to the                            
18
// Free Software Foundation, Inc., 51 Franklin Street,                      
19
// Fifth Floor, Boston, MA  02110-1301, USA.                                
20
// -------------------------------------------                              
21
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
22
//=================================================================
23
//
24
//        eCosTest.cpp
25
//
26
//        Test class
27
//
28
//=================================================================
29
//=================================================================
30
//#####DESCRIPTIONBEGIN####
31
//
32
// Author(s):     sdf
33
// Contributors:  sdf, jld
34
// Date:          1999-04-01
35
// Description:   This class abstracts a test for use in the testing infrastructure
36
// Usage:
37
//
38
//####DESCRIPTIONEND####
39
///////////////////////////////////////////////////////////////////////////////
40
#include "eCosStd.h"
41
#include "eCosTest.h"
42
#include "eCosTestPlatform.h"
43
#include "eCosTrace.h"
44
#include "TestResource.h"
45
#include "eCosTestUtils.h"
46
#include "eCosSocket.h"
47
#include "eCosSerial.h"
48
#include "eCosTestSerialFilter.h"
49
#include "eCosTestDownloadFilter.h"
50
#include "Properties.h"
51
#include "Subprocess.h"
52
 
53
#ifdef __CYGWIN__
54
#include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() */
55
#endif
56
 
57
#define WF(n) (n+50)/1000,((n+50)%1000)/100     // Present n as whole and fractional part.  Round to nearest least significant digit
58
#define WFS   _T("%u.%u")                           // The format string to output the above
59
 
60
LPCTSTR  const CeCosTest::arResultImage[1+CeCosTest::StatusTypeMax]=
61
{_T("NotStarted"), _T("NoResult"), _T("Inapplicable"), _T("Pass"), _T("DTimeout"), _T("Timeout"), _T("Cancelled"), _T("Fail"), _T("AssertFail"), _T("Unknown")};
62
 
63
CeCosTest *CeCosTest::pFirstInstance=0;
64
int CeCosTest::InstanceCount=0;
65
 
66
LPCTSTR  const CeCosTest::arServerStatusImage[1+CeCosTest::ServerStatusMax]={
67
  _T("Busy"), _T("Ready"), _T("Can't run"), _T("Connection failed"), _T("Locked"), _T("Bad server status")};
68
LPCTSTR  CeCosTest::ExecutionParameters::arRequestImage [1+ExecutionParameters::RequestTypeMax]={
69
  _T("Run"), _T("Query"), _T("Lock"), _T("Unlock"), _T("Stop"), _T("Bad request") };
70
 
71
static bool CALLBACK IsCancelled(void *pThis)
72
{
73
  return CeCosTest::Cancelled==((CeCosTest *)pThis)->Status();
74
}
75
 
76
// Ctors and dtors:
77
CeCosTest::CeCosTest(const ExecutionParameters &e, LPCTSTR pszExecutable,LPCTSTR pszTitle):
78
  m_pspPipe(0),
79
  m_nStrippedSize(0),
80
  m_nFileSize(0),
81
  m_bDownloading(false),
82
  m_pSock(0),
83
  m_ep(e),
84
  m_strTitle(pszTitle),
85
  m_Status(NotStarted),
86
  m_nDownloadTime(0),
87
  m_nTotalTime(0),
88
  m_nMaxInactiveTime(0),
89
  m_pResource(0),
90
  m_psp(0)
91
{
92
 
93
  assert(e.Platform());
94
 
95
  SetExecutable (pszExecutable);
96
 
97
  TRACE(_T("%%%% Create test instance %08x count:=%d\n"),this,InstanceCount+1);
98
 
99
  // By recording the path now, we ensure processes are always run in the context in which the test instance
100
  // is created (important for the ConfigTool to be able to call PrepareEnvironment).
101
 
102
#ifdef _WIN32
103
  // for some reason _tgetenv() doesn't return the PATH set
104
  // by PrepareEnvironment() so use GetEnvironmentVariable() instead
105
  // JLD - 2000-06-09
106
  String strPath;
107
  int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0);
108
  GetEnvironmentVariable(_T("PATH"), strPath.GetBuffer(nSize), nSize);
109
  strPath.ReleaseBuffer();
110
  m_strPath=strPath;
111
#else
112
  LPCTSTR pszPath=_tgetenv(_T("PATH"));
113
  if(pszPath){
114
    m_strPath=pszPath;
115
  }
116
#endif
117
 
118
  ENTERCRITICAL;
119
  InstanceCount++;
120
  m_pNextInstance=pFirstInstance;
121
  if(m_pNextInstance){
122
    m_pNextInstance->m_pPrevInstance=this;
123
  }
124
  m_pPrevInstance=0;
125
  pFirstInstance=this;
126
  LEAVECRITICAL;
127
 
128
}
129
 
130
CeCosTest::~CeCosTest()
131
{
132
  for(int i=0;i<(signed)m_arpExecsp.size();i++){
133
    delete (CSubprocess *)m_arpExecsp[i];
134
  }
135
  delete m_pspPipe;
136
 
137
  TRACE(_T("%%%% Delete test instance %08x\n"),this);
138
  Cancel();
139
  CloseSocket();
140
  if(m_pResource){
141
    m_pResource->Release();
142
    //delete m_pResource;
143
    //m_pResource=0;
144
  }
145
 
146
  VTRACE(_T("~CeCosTest(): EnterCritical and decrease instance count\n"));
147
  ENTERCRITICAL;
148
  InstanceCount--;
149
  TRACE(_T("%%%% Destroy instance.  Instance count:=%d\n"),InstanceCount);
150
  if(pFirstInstance==this){
151
    pFirstInstance=m_pNextInstance;
152
  }
153
  if(m_pPrevInstance){
154
    m_pPrevInstance->m_pNextInstance=m_pNextInstance;
155
  }
156
  if(m_pNextInstance){
157
    m_pNextInstance->m_pPrevInstance=m_pPrevInstance;
158
  }
159
  LEAVECRITICAL;
160
}
161
 
162
bool CeCosTest::RunRemote (LPCTSTR pszRemoteHostPort)
163
{
164
  bool rc=false;
165
  TRACE(_T("RunRemote\n"));
166
  m_strExecutionHostPort=pszRemoteHostPort;
167
  m_Status=NotStarted;
168
 
169
  VTRACE(_T("RemoteThreadFunc()\n"));
170
 
171
  // Find a server.
172
  ConnectForExecution();
173
  if(Cancelled!=Status()){
174
    if(m_ep.Platform()->ServerSideGdb()){
175
      // The executable is transmitted to the server for execution.
176
      // Send file size
177
      if(m_pSock->sendInteger(m_nFileSize,_T("file size"))&&m_nFileSize>0){
178
        int nBufSize=MIN(10000,m_nFileSize);
179
        Buffer b(nBufSize);
180
        TRACE(_T("Sending [%d bytes]\n"), m_nFileSize);
181
        int nToSend=m_nFileSize;
182
        FILE *f1=_tfopen(m_strExecutable,_T("rb"));
183
        if(0==f1){
184
          Log(_T("Failed to open %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
185
        } else {
186
          while (nToSend>0){
187
            int nRead=fread( b.Data(), 1, nBufSize, f1);
188
            if(nRead<=0){
189
              Log(_T("Failure reading %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
190
              break;
191
            }
192
            if(!send( b.Data(), nRead, _T("executable"))){
193
              Log(_T("Failure sending %s - %s\n"),(LPCTSTR)m_strExecutable,(LPCTSTR)m_pSock->SocketErrString());
194
              break;
195
            }
196
            nToSend-=nRead;
197
          }
198
          fclose(f1);
199
          f1=0;
200
          if(nToSend>0){
201
            TRACE(_T("done [%d bytes sent]\n"),m_nFileSize-nToSend);
202
            Log(_T("Failed to transmit %s - %d/%d bytes sent\n"),(LPCTSTR)m_strExecutable,m_nFileSize-nToSend,m_nFileSize);
203
          } else {
204
            TRACE(_T("done\n"));
205
            rc=true;
206
          }
207
        }
208
        if(!recvResult(9*1000*60)){ // nine minutes
209
          Log(_T("Failed to receive result from remote server\n"));
210
          rc=false;
211
        }
212
        m_pSock->sendInteger(456); // send an ack [n'importe quoi]
213
        CloseSocket();
214
      }
215
    } else {
216
      // The server sets up a connection between port and tcp/ip socket, and gdb is run locally
217
      // Big timeout here because we have to wait for the target to be reset
218
      // We do this:
219
      // do {
220
      //     target ready indicator (0==fail, 1==ready, 2==fail and will retry)
221
      //     any output so far
222
      // } while (2==target ready indicator)
223
      // read host:port
224
      String strHostPort;
225
      if(GetTargetReady(strHostPort)){
226
        // Fix up a resource to represent permission to use the host:port we have been told about
227
        CTestResource resource;
228
        resource.SetTarget(m_ep.PlatformName());
229
        resource.SetDownload(strHostPort,0);
230
        m_pResource=&resource;
231
        RunLocal();
232
        m_pResource=0;
233
        m_pSock->sendInteger(Status(),_T("Terminating ack"));
234
        m_pSock->Close();
235
        rc=true;
236
      }
237
    }
238
  }
239
  TRACE(_T("RemoteThreadFunc - exiting\n"));
240
  return rc;
241
}
242
 
243
// Run the test locally
244
bool CeCosTest::RunLocal()
245
{
246
  bool rc=false;
247
 
248
  TRACE(_T("RunLocal %s\n"),(LPCTSTR)Executable());
249
 
250
  if(!CeCosTestUtils::IsFile(Executable())){
251
    Log(_T("Cannot run - %s is not a file\n"),(LPCTSTR)Executable());
252
  } else if(0==m_pResource && 0==CTestResource::Count(m_ep)){
253
    Log(_T("Cannot run a %s test\n"),(LPCTSTR)m_ep.PlatformName());
254
  } else {
255
 
256
    m_Status=NotStarted;
257
 
258
    TRACE(_T("LocalThreadFunc - target=%s\n"),(LPCTSTR)m_ep.PlatformName());
259
    // Acquire a port (our caller may have done this for us)
260
    VTRACE(_T("LocalThreadFunc():Trying to acquire a port\n"));
261
    if(0==m_pResource){
262
      for(;;){
263
        m_pResource=CTestResource::GetResource(m_ep);
264
        if(m_pResource||Cancelled==Status()){
265
          break;
266
        }
267
        CeCosThreadUtils::Sleep(2000);
268
        TRACE(_T("Waiting for a port\n"));
269
      }
270
    }
271
    VTRACE(_T("\nPort acquired!\n"));
272
 
273
    if(Cancelled!=Status()){
274
      // This means we have acquired a local port 
275
      bool bTargetReady=false;
276
      if(!m_pResource->HasReset()){
277
        bTargetReady=true;
278
      } else {
279
        bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(0,this));
280
      }
281
      // we may proceed to execute the test
282
      if(bTargetReady){
283
        SetStatus(NotStarted);
284
 
285
        if(NOTIMEOUT==m_ep.DownloadTimeout()){
286
          // No elapsed timeout given - calculate from knowledge of executable size and baud rate
287
          // 10 baud ~= 1 byte/sec, but we halve this to account for download in hex :-(
288
          // We use a minimum of 30 seconds and double the calculated result for safety
289
          // Note that the baud rate is generally unknown on the client side.
290
          int nBaud=m_pResource->Baud();
291
          if(0==nBaud){
292
            CTestResource *pExecutionResource=CTestResource::Lookup(m_strExecutionHostPort);
293
            if(pExecutionResource){
294
              nBaud=pExecutionResource->Baud();
295
            }
296
          }
297
          if(0==nBaud){
298
            nBaud=38400;
299
          }
300
 
301
          int nBytesPerSec=(nBaud/10)/2; // division by 2 assumes download in "ascii" (2 bytes/char)
302
          m_ep.SetDownloadTimeout (1000*MAX(30,2*(m_nStrippedSize/nBytesPerSec)));
303
          TRACE(_T("Estimated download time %d sec (%d bytes @ %d bytes/sec [%d baud])\n"),m_nStrippedSize/nBytesPerSec,m_nStrippedSize,nBytesPerSec,nBaud);
304
        }
305
 
306
        TRACE(_T("Active timeout=%d download timeout=%d\n"),m_ep.ActiveTimeout(), m_ep.DownloadTimeout());
307
 
308
        GetInferiorCommands(m_arstrInferiorCmds);
309
        String strInferior(m_ep.Platform()->Inferior());
310
        strInferior.Replace(_T("%e"),CygPath(m_strExecutable),true);
311
        RunInferior(strInferior);
312
        rc=true;
313
      }
314
    }
315
    if(m_pResource){
316
      m_pResource->Release();
317
      m_pResource=0;
318
    }
319
    TRACE(_T("RunLocal - exiting\n"));
320
  }
321
 
322
  return rc;
323
}
324
 
325
void CeCosTest::Cancel ()
326
{
327
  SetStatus(Cancelled);
328
}
329
 
330
CeCosTest::ServerStatus CeCosTest::Connect (LPCTSTR pszHostPort, CeCosSocket *&pSock, const ExecutionParameters &e,String &strInfo,Duration dTimeout)
331
{
332
  // Find out whether this host is receptive
333
  ServerStatus s=CONNECTION_FAILED;
334
  pSock=new CeCosSocket(pszHostPort,dTimeout);
335
  int nStatus;
336
  if(pSock->Ok() &&
337
    pSock->sendString(e.Image(), _T("execution parameters")) &&
338
    pSock->recvInteger(nStatus,_T("ready status")) &&
339
    pSock->recvString(strInfo)){
340
    s=(ServerStatus)MIN(nStatus,ServerStatusMax);
341
  }
342
  if(SERVER_READY!=s || ExecutionParameters::RUN!=e.Request()){
343
    delete pSock;
344
    pSock=0;
345
  }
346
  return s;
347
}
348
 
349
// Initiate a connection to hostName:nPort and acquire the ready status [retry until this is achieved]
350
// The socket (m_pSock) is left open.
351
// This function is either called with m_strExecutionHostPort already set to a desired server
352
// or else m_strExecutionHostPort empty (in which case the server is / dynamically)
353
 
354
void CeCosTest::ConnectForExecution ()
355
{
356
  bool bSchedule=(0==m_strExecutionHostPort.size());
357
  Duration nDelay=2000;
358
 
359
  m_pSock=0;
360
 
361
  bool *arbHostTried=0;
362
 
363
  while(Cancelled!=Status()){
364
    StringArray arstrHostPort,arstrTries;
365
    int nChoices;
366
 
367
    if(bSchedule){
368
      if(!CTestResource::GetMatches(m_ep,arstrHostPort)){
369
        Log(_T("Could not establish matches\n"));
370
        continue;
371
      }
372
      nChoices=arstrHostPort.size();
373
      if(nChoices>0){
374
        TRACE(_T("ConnectForExecution: choices are:\n"));
375
        for(int i=0;i<nChoices;i++){
376
          TRACE(_T("\t%s\n"),(LPCTSTR)arstrHostPort[i]);
377
        }
378
      }
379
    } else {
380
      // Server has already been picked by caller
381
      nChoices=1;
382
      String str;
383
      arstrHostPort.push_back(m_strExecutionHostPort);
384
    }
385
 
386
    if(nChoices>0){
387
      delete [] arbHostTried;
388
      arbHostTried=new bool[nChoices];
389
      for(int i=0;i<nChoices;i++){
390
        arbHostTried[i]=false;
391
      }
392
 
393
      // Loop around the choices
394
      for(int nUntried=nChoices;nUntried>0;nUntried--) {
395
        // Select one we haven't tried already:
396
        int nChoice;
397
        do {
398
          nChoice=rand() % nChoices;
399
        } while (arbHostTried[nChoice]);
400
 
401
        m_strExecutionHostPort=arstrHostPort[nChoice];
402
 
403
        TRACE(_T("ConnectForExecution: chosen %s\n"),(LPCTSTR)m_strExecutionHostPort);
404
        if(CeCosSocket::IsLegalHostPort(m_strExecutionHostPort)){
405
          // If we're using the resource server we had better check that the host
406
          // we are about to lock has not been resource-locked (the other match checks
407
          // will of course always succeed)
408
          String strInfo;
409
          ServerStatus s=bSchedule && !CTestResource::Matches(m_strExecutionHostPort,m_ep)?SERVER_LOCKED:
410
            Connect(m_strExecutionHostPort,m_pSock,m_ep,strInfo);
411
          arbHostTried[nChoice]=true;
412
          TRACE(_T("Connect: %s says %s %s\n"),(LPCTSTR)m_strExecutionHostPort,(LPCTSTR)Image(s),(LPCTSTR)strInfo);
413
          CTestResource *pResource=CTestResource::Lookup(m_strExecutionHostPort);
414
          if(pResource){
415
            String str;
416
            str.Format(_T("%s %s %s"),(LPCTSTR)pResource->Image(),(LPCTSTR)strInfo,(LPCTSTR)Image(s));
417
            arstrTries.push_back(str);
418
          }
419
          if(SERVER_READY==s){
420
            // So that's ok then.  We're outta here.
421
            INTERACTIVE(_T("Connected to %s\n"),(LPCTSTR)m_strExecutionHostPort);
422
            goto Done;
423
          } else {
424
            delete m_pSock;
425
            m_pSock=0;
426
          }
427
        }
428
      }
429
    }
430
 
431
    INTERACTIVE(_T("Warning - could not connect to any test servers:\n"));
432
    if(arstrTries.size()>0){
433
      for(unsigned int i=0;i<arstrTries.size();i++){
434
        INTERACTIVE(_T("    %s\n"),(LPCTSTR)arstrTries[i]);
435
      }
436
    } else {
437
      INTERACTIVE(_T("No servers available to execute %s test:\n"),(LPCTSTR)m_ep.PlatformName());
438
      ENTERCRITICAL;
439
      for(CTestResource *pResource=CTestResource::First();pResource;pResource=pResource->Next()){
440
        INTERACTIVE(_T("    %s\n"),(LPCTSTR)pResource->Image());
441
      }
442
      LEAVECRITICAL;
443
    }
444
    INTERACTIVE(_T("Retry in %d seconds...\n"),nDelay/1000);
445
 
446
    // We have tried all possibilities - sleep before retrying
447
    CeCosThreadUtils::Sleep(nDelay);
448
 
449
    if(Cancelled==m_Status){
450
      TRACE(_T("ConnectForExecution : cancelled\n"));
451
      goto Done;
452
    }
453
    if(nDelay<20*1000){
454
      nDelay+=rand() % 500;
455
    }
456
  }
457
Done:
458
  delete [] arbHostTried;
459
}
460
 
461
void CeCosTest::SetStatus (StatusType status)
462
{
463
  ENTERCRITICAL;
464
  if((int)status>(int)m_Status){
465
    TRACE(_T("Status <- %s\n"),(LPCTSTR)Image(status));
466
    m_Status=status;
467
  }
468
  LEAVECRITICAL;
469
}
470
 
471
bool CeCosTest::WaitForAllInstances(int nPoll,Duration nTimeout)
472
{
473
  Time t0=Now();
474
  while(InstanceCount>0){
475
    CeCosThreadUtils::Sleep(nPoll);
476
    if(NOTIMEOUT!=nTimeout && Now()-t0>nTimeout){
477
      return false;
478
    }
479
  }
480
  return true;
481
}
482
 
483
void CeCosTest::DeleteAllInstances()
484
{
485
  while(pFirstInstance){
486
    delete pFirstInstance;
487
  }
488
}
489
 
490
void CeCosTest::CancelAllInstances()
491
{
492
  ENTERCRITICAL;
493
  for(CeCosTest *pTest=pFirstInstance;pTest;pTest=pTest->m_pNextInstance){
494
    pTest->Cancel();
495
  }
496
  LEAVECRITICAL;
497
}
498
 
499
// The same format is used for _stscanf as for Format (which is like printf), so restrict to the format specifiers
500
// the former is happy with.  In particular, do not use %-3s etc...
501
 
502
LPCTSTR CeCosTest::pszFormat=
503
// 1999-01-15 17:24:36 Fireblade:5002 MN10300 sin.exe 219k/134k Pass sin download=106.3/117.0 Total=107.6 Max inactive=1.0/300.0    
504
_T("%04d-%02d-%02d %02d:%02d:%02d ")                   // Time
505
_T("%15s ")                                            // Execution host:port
506
_T("%16s ")                                             // Target
507
_T("%30s ")                                            // Executable tail
508
_T("%11s ")                                            // Result
509
_T("%dk/%dk ")                                         // Sizes
510
_T("D=") WFS _T("/") WFS _T(" Total=") WFS _T(" ")     // Times
511
_T("E=") WFS _T("/") WFS _T(" ")
512
_T("\"%s\"");
513
 
514
bool CeCosTest::Value (
515
  LPCTSTR pszStr,
516
  struct tm &t,
517
  StatusType &status,
518
  String &target,
519
  String &strExecutionHostPort,
520
  String &strExecutableTail,
521
  String &strTitle,
522
 
523
  int &nFileSize,
524
  Duration &nTotalTime,
525
  Duration &nMaxInactiveTime,
526
  Duration &nDownloadTime,
527
  Duration &nDownloadTimeout,
528
  Duration &nActiveTimeout,
529
 
530
  int &nDownloadedSize)
531
{
532
  int nLen=_tcslen(pszStr);
533
  String strStatus;
534
 
535
  nFileSize=nTotalTime=nMaxInactiveTime=nDownloadTime=nDownloadTimeout=nActiveTimeout=nDownloadedSize=0;
536
 
537
  int nTotalTimeFrac=0;
538
  int nMaxInactiveTimeFrac=0;
539
  int nActiveTimeoutFrac=0;
540
  int nDownloadTimeFrac=0;
541
  int nDownloadTimeoutFrac=0;
542
 
543
  static String strFormat;
544
  if(0==strFormat.size()){
545
    // Construct a version of the format string sans length attributes for %s items
546
    LPCTSTR c=pszFormat;
547
    TCHAR *d=strFormat.GetBuffer(_tcslen(pszFormat));
548
    while(_TCHAR('\0')!=*c){
549
      if(_TCHAR('%')==c[0] && _istdigit(c[1])){
550
        *d++=_TCHAR('%');
551
        do {
552
          c++;
553
        } while (_istdigit(*c));
554
      }
555
      *d++=*c++;
556
    }
557
    *d=_TCHAR('\0');
558
    strFormat.ReleaseBuffer();
559
  }
560
 
561
  _stscanf(pszStr,
562
    strFormat,
563
    &t.tm_year,&t.tm_mon,&t.tm_mday,
564
    &t.tm_hour,&t.tm_min,&t.tm_sec,         // Time of day
565
    strExecutionHostPort.GetBuffer(1+nLen),       // Execution host:port
566
    target.GetBuffer(1+nLen),                  // Target
567
    strExecutableTail.GetBuffer(1+nLen),          // Executable
568
    strStatus.GetBuffer(1+nLen),                  // Result
569
    &nDownloadedSize,&nFileSize,            // Sizes
570
    &nDownloadTime,&nDownloadTimeFrac,      // Times
571
    &nDownloadTimeout,&nDownloadTimeoutFrac,
572
    &nTotalTime,&nTotalTimeFrac,
573
    &nMaxInactiveTime,&nMaxInactiveTimeFrac,
574
    &nActiveTimeout,&nActiveTimeoutFrac,
575
    strTitle.GetBuffer(1+nLen)                    // Title
576
    );
577
 
578
  strExecutionHostPort.ReleaseBuffer();
579
  target.ReleaseBuffer();
580
  strExecutableTail.ReleaseBuffer();
581
  strStatus.ReleaseBuffer();
582
  strTitle.ReleaseBuffer();
583
  status=StatusTypeValue(strStatus);
584
 
585
  LPCTSTR c1=_tcschr(pszStr,_TCHAR('"'));
586
  if(c1){
587
    c1++;
588
    LPCTSTR c2=_tcschr(c1+1,_TCHAR('"'));
589
    if(c2){
590
      strTitle=String(c1,c2-c1);
591
    }
592
  }
593
 
594
  nTotalTime=nTotalTime*1000+nTotalTimeFrac*100;
595
  nMaxInactiveTime=nMaxInactiveTime*1000+nMaxInactiveTimeFrac*100;
596
  nActiveTimeout=nActiveTimeout*1000+nActiveTimeoutFrac*100;
597
  nDownloadTime=nDownloadTime*1000+nDownloadTimeFrac*100;
598
  nDownloadTimeout=nDownloadTimeout*1000+nDownloadTimeoutFrac*100;
599
 
600
  nFileSize*=1024;
601
  nDownloadedSize*=1024;
602
  t.tm_year-=1900;
603
  t.tm_mon--;
604
  return t.tm_year>=0 && t.tm_year<=200 && t.tm_mon>=0 && t.tm_mon<=11 && t.tm_mday>=1 && t.tm_mday<=31 && t.tm_hour>=0 && t.tm_hour<=23 && t.tm_min>=0 && t.tm_min<=59 && t.tm_sec>=0 && t.tm_sec<=59 &&
605
    status!=StatusTypeMax
606
    //&& exetype!=ExecutionParameters::ExecutableTypeMax
607
    ;
608
}
609
 
610
const String CeCosTest::ResultString(bool bIncludeOutput) const
611
{
612
  String strResultString;
613
  String strTitle(m_strTitle);
614
  String strExecutionHostPort(m_strExecutionHostPort);
615
 
616
  if(0==strTitle.size()){
617
    strTitle=CeCosSocket::MySimpleHostName();
618
    strTitle+=_TCHAR(':');
619
    strTitle+=m_strExecutable;
620
  }
621
 
622
  if(0==strExecutionHostPort.size()){
623
    strExecutionHostPort=CeCosSocket::MySimpleHostName();
624
    strExecutionHostPort+=_T(":0");
625
  }
626
 
627
  ENTERCRITICAL;
628
  time_t ltime;
629
  time(&ltime);
630
  struct tm *now=localtime( &ltime );
631
 
632
  strResultString.Format(
633
    pszFormat,
634
    1900+now->tm_year,1+now->tm_mon,now->tm_mday,
635
    now->tm_hour,now->tm_min,now->tm_sec,               // Time of day
636
    (LPCTSTR)strExecutionHostPort,                      // Execution host:port
637
    (LPCTSTR)m_ep.PlatformName(),                       // Target
638
    (LPCTSTR)CeCosTestUtils::Tail(m_strExecutable),     // Executable
639
    (LPCTSTR)Image(Status()),                           // Result
640
    m_nStrippedSize/1024,m_nFileSize/1024,              // Sizes
641
    WF(m_nDownloadTime),WF(m_ep.DownloadTimeout()),WF(m_nTotalTime),// Times
642
    WF(m_nMaxInactiveTime),WF(m_ep.ActiveTimeout()),
643
    (LPCTSTR)strTitle                                   // Title
644
    );
645
  if(bIncludeOutput && m_strOutput.size()>0){
646
    strResultString+=_TCHAR('\n');
647
    strResultString+=m_strOutput;
648
  }
649
  LEAVECRITICAL;
650
  return strResultString;
651
}
652
 
653
// Run as a server, listening on the port given as parameter
654
bool CeCosTest::RunAgent(int nTcpPort)
655
{
656
  bool bLocked=false;
657
 
658
  // Create socket
659
  int nSock = CeCosSocket::Listen(nTcpPort);
660
  int nLastClient=0;
661
  if (-1!=nSock) {
662
    for (;;) {
663
      try {
664
        CeCosSocket *pSock=new CeCosSocket(nSock); // AcceptThreadFunc deletes if not deleted below
665
        String str;
666
        // Read the execution parameters
667
        if(!pSock->recvString(str)){
668
          // Socket error on the recv - nothing much we can do
669
          TRACE(_T("RunAgent : could not read execution parameters\n"));
670
          delete pSock;
671
          pSock=0;
672
        } else {
673
          ExecutionParameters e;
674
          e.FromStr(str);
675
          TRACE(_T("Execution parameters: %s\n"),(LPCTSTR)e.Image());
676
          ServerStatus s;
677
          CTestResource *pPort=0;
678
          String strInfo;
679
 
680
          switch(e.Request()) {
681
            case ExecutionParameters::LOCK:
682
              if(bLocked){
683
                s=SERVER_BUSY;
684
              } else {
685
                WaitForAllInstances(1000,NOTIMEOUT);
686
                bLocked=true;
687
                s=SERVER_LOCKED;
688
              }
689
              break;
690
            case ExecutionParameters::UNLOCK:
691
              if(bLocked){
692
                bLocked=false;
693
                s=SERVER_READY;
694
              } else {
695
                s=SERVER_BUSY;
696
              }
697
              break;
698
            case ExecutionParameters::QUERY:
699
              if (bLocked) {
700
                s=SERVER_LOCKED;
701
              } else {
702
                s=SERVER_BUSY;
703
                ENTERCRITICAL;
704
                for(CTestResource *pResource=CTestResource::First();pResource;pResource=pResource->Next()){
705
                  if(!pResource->InUse()){
706
                    s=SERVER_READY;
707
                    break;
708
                  }
709
                }
710
                LEAVECRITICAL;
711
                if(SERVER_READY!=s){
712
                  strInfo.Format(_T("serving %s"),(LPCTSTR)CeCosSocket::ClientName(nLastClient));
713
                }
714
              }
715
              break;
716
            case ExecutionParameters::RUN:
717
              if(NULL==e.Platform()){
718
                // Looks like a confused client ...
719
                strInfo.Format(_T("Bad target value %s read from client\n"),(LPCTSTR)str);
720
                s=SERVER_CANT_RUN;
721
              } else if(0==CTestResource::Count(e)){
722
                // No chance of running this test
723
                strInfo.Format(_T("Cannot run a %s test from this server\n"),(LPCTSTR)e.PlatformName());
724
                s=SERVER_CANT_RUN;
725
              } else if (bLocked) {
726
                s=SERVER_LOCKED;
727
              } else {
728
                pPort=CTestResource::GetResource(e);
729
                if(0==pPort){
730
                  // We must disappoint our client
731
                  strInfo.Format(_T("serving %s"),(LPCTSTR)CeCosSocket::ClientName(nLastClient));
732
                  s=SERVER_BUSY;
733
                } else {
734
                  s=SERVER_READY;
735
                  nLastClient=pSock->Client();
736
                }
737
              }
738
              break;
739
            case ExecutionParameters::STOP:
740
              s=SERVER_READY;
741
              break;
742
            default:
743
              s=SERVER_CANT_RUN;
744
          }
745
 
746
#ifndef VERBOSE
747
          if(ExecutionParameters::QUERY!=e.Request())
748
#endif
749
            TRACE(_T("RunAgent : %s request tActive=%d tDownload=%d Target=%s Reply status=%s %s\n"),
750
              (LPCTSTR)e.Image(e.Request()),e.ActiveTimeout(),e.DownloadTimeout(),
751
              (LPCTSTR)e.PlatformName(),
752
              (LPCTSTR)Image(s),(LPCTSTR)strInfo);
753
 
754
          bool bSendok=pSock->sendInteger(s) && pSock->sendString(strInfo);
755
 
756
          if(SERVER_READY==s && bSendok && ExecutionParameters::RUN==e.Request()){
757
 
758
            // Create a new class instance
759
            // AcceptThreadFunc deletes the instance and closes new_sock
760
            // RunLocal, called by AcceptThreadFunc, releases the port
761
            // No need for meaningful callback, but must run asynchronously
762
 
763
            int nAuxPort=30000;
764
            int nAuxListenSock=-1;
765
 
766
            do {
767
              nAuxListenSock=CeCosSocket::Listen(nAuxPort);
768
            } while (-1==nAuxListenSock && nAuxPort++<=0xffff);
769
 
770
            if(-1==nAuxListenSock){
771
              ERROR(_T("Couldn't find a socket to bind to for RDI\n"));
772
            } else {
773
 
774
              CeCosTest *pTest=new CeCosTest(e,NULL);
775
              pTest->m_nAuxPort=nAuxPort;
776
              pTest->m_nAuxListenSock=nAuxListenSock;
777
              pTest->m_pSock=pSock;
778
              pTest->m_strExecutionHostPort=CeCosSocket::HostPort(CeCosSocket::MyHostName(),nTcpPort);
779
              pTest->m_pResource=pPort;
780
              CeCosThreadUtils::RunThread(SAcceptThreadFunc,pTest,_T("SAcceptThreadFunc"));
781
              // AcceptThreadFunc deletes pSock
782
            }
783
 
784
          } else {
785
            delete pSock;
786
            pSock=0;
787
            if(pPort){
788
              pPort->Release();
789
              pPort=0;
790
            }
791
            if(CeCosTest::ExecutionParameters::STOP==e.Request()){
792
              CancelAllInstances();
793
              WaitForAllInstances(1000,20*1000);
794
              break;
795
            }
796
          }
797
        }
798
      }
799
      catch(...){
800
        TRACE(_T("!!! Exception caught in RunAgent()\n"));
801
      }
802
    }
803
    CeCosSocket::CloseSocket (nSock);
804
  }
805
 
806
  return false;
807
}
808
 
809
CeCosTest::StatusType CeCosTest::StatusTypeValue(LPCTSTR  pszStr)
810
{
811
  for(int i=0;i<StatusTypeMax;i++){
812
    StatusType t=(StatusType)i;
813
    if(0==_tcsicmp(Image(t),pszStr)){
814
      return t;
815
    }
816
  }
817
  return StatusTypeMax;
818
}
819
 
820
// Thread to run ConnectSocketToSerial
821
void CeCosTest::ConnectSocketToSerialThreadFunc()
822
{
823
  TRACE(_T("ConnectSocketToSerialThreadFunc sock=%d\n"),m_nAuxListenSock);
824
 
825
  CeCosTestSerialFilter serial_filter;
826
  CeCosTestDownloadFilter download_filter;
827
 
828
  CeCosSerial serial;
829
  serial.SetBlockingReads(false);
830
  bool rc=false;
831
  // Open serial device.
832
  if (!serial.Open(m_pResource->Serial(),m_pResource->Baud())){
833
    ERROR(_T("Couldn't open port %s\n"),m_pResource->Serial());
834
  } else {
835
    for(;;){
836
      // Flush the serial buffer.
837
      serial.Flush();
838
      TRACE(_T("ConnectSocketToSerial: waiting for connection...\n"));
839
      CeCosSocket socket;
840
      if(!socket.Accept(m_nAuxListenSock,&m_bStopConnectSocketToSerial)){
841
        ERROR(_T("ConnectSocketToSerial - couldn't accept: %s\n"),(LPCTSTR)socket.SocketErrString());
842
        break;
843
      } else if (m_pSock->Client() != socket.Client()){
844
        // Make sure the client is who we think it is...
845
        TRACE(_T("ConnectSocketToSerialThread - illegal connection attempted from %s\n"),(LPCTSTR)socket.ClientName(socket.Client()));
846
      } else {
847
        try {
848
            rc=CeCosSocket::ConnectSocketToSerial(socket,serial,m_ep.m_bUseFilter?SerialFilterFunction:NULL, (void*)&serial_filter, m_ep.m_bUseFilter?DownloadFilterFunction:NULL, (void*)&download_filter, &m_bStopConnectSocketToSerial);
849
 
850
          // If the download filter was just active, it may
851
          // allow the session to continue.
852
          if(!download_filter.ContinueSession()){
853
            break;
854
          }
855
 
856
        }
857
        catch (LPCTSTR pszMsg){
858
          Log(_T("!!! ConnectSocketToSerial exception caught: %s!!!\n"),pszMsg);
859
          rc=false;
860
          break;
861
        }
862
        catch (...){
863
          Log(_T("!!! ConnectSocketToSerial exception caught!!!\n"));
864
          rc=false;
865
          break;
866
        }
867
      }
868
    }
869
  }
870
  TRACE(_T("ConnectSocketToSerial : done\n"));
871
  CeCosSocket::CloseSocket(m_nAuxListenSock);
872
}
873
 
874
static bool CALLBACK DerefBool(void *pParam)
875
{
876
  return *(bool *)pParam;
877
}
878
 
879
// Function called (on a separate thread) to process a successful connection to the RunAgent loop
880
// In the case of a simulator server, we can have many of these active at the same time.
881
void CeCosTest::AcceptThreadFunc()
882
{
883
  if(m_ep.Platform()->ServerSideGdb()){
884
    // We dream up a temporary name for the executable
885
    ENTERCRITICAL;
886
    m_strExecutable.Format(_T("%s-%s-%d"),_ttmpnam(0),(LPCTSTR)m_ep.PlatformName(),m_nAuxPort);
887
    LEAVECRITICAL;
888
 
889
    int n;
890
    if(m_pSock->recvInteger(n,_T("file size"))){
891
      m_nFileSize=n;
892
      // Read file from the socket
893
      bool bCanRun=true;
894
      TRACE(_T("AcceptThreadFunc file size=%d reading...\n"),m_nFileSize);
895
      FILE *f2;
896
      f2=_tfopen(m_strExecutable,_T("wb"));
897
      if(0==f2){
898
        Log(_T("Could not create %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
899
        bCanRun=false;
900
      }
901
      unsigned int nBufSize=MIN(100000,m_nFileSize);
902
      Buffer b(nBufSize);
903
      unsigned int nWritten=0;
904
      unsigned int nRead=0;
905
      while(nRead<m_nFileSize){
906
        int nToRead=MIN(nBufSize,m_nFileSize-nRead);
907
        if(!recv( b.Data(), nToRead, _T("executable"))){
908
          break;
909
        }
910
        nRead+=nToRead;
911
        if(0!=f2){
912
          char *c=(char *)b.Data();
913
          while(nToRead>0){
914
            int w=fwrite(c,1,nToRead,f2);
915
            if(-1==w){
916
              Log(_T("Write error on %s - %s\n"),(LPCTSTR)m_strExecutable,strerror(errno));
917
              bCanRun=false;
918
              break;
919
            }
920
            nWritten+=w;
921
            c+=w;
922
            nToRead-=w;
923
          }
924
        }
925
      }
926
      TRACE(_T("Accept - done reading [%d bytes read, %d bytes written]\n"),nRead,nWritten);
927
      if(0!=f2){
928
        fclose(f2);
929
        _tchmod(m_strExecutable,00700); // user read, write and execute
930
      }
931
      if(0!=f2 && m_nFileSize!=nWritten){
932
        Log(_T("Failed to create %s correctly [%d/%d bytes written]\n"),(LPCTSTR)m_strExecutable, nWritten, m_nFileSize);
933
        bCanRun=false;
934
      }
935
      SetExecutable(m_strExecutable); // to set stripped length and title
936
      RunLocal();
937
      _tunlink(m_strExecutable);
938
    }
939
    sendResult();
940
    m_pSock->recvInteger(n); // receive an ack
941
  } else {
942
    // Client-side GDB
943
    bool bTargetReady;
944
    if(_TCHAR('\0')==*(m_pResource->ResetString())){
945
      bTargetReady=true;
946
      TRACE(_T("No reset possible\n"));
947
    } else {
948
      Log(_T("Resetting target using %s"),(LPCTSTR)m_pResource->ResetString());
949
      bTargetReady=(CResetAttributes::RESET_OK==m_pResource->Reset(ResetLogFunc,this));
950
    }
951
    TRACE(_T("Send Target Ready indicator=%d\n"),bTargetReady);
952
    m_pSock->sendInteger(bTargetReady,_T("target ready indicator"));
953
 
954
    int nAck=-1;
955
 
956
    if(bTargetReady){
957
      if(CeCosSocket::IsLegalHostPort(m_pResource->Serial())){
958
        TRACE(_T("Sending %s\n"),(LPCTSTR)m_pResource->Serial());
959
        if(m_pSock->sendString(m_pResource->Serial(),_T("Serial name")) && m_pSock->recvInteger(nAck,_T("Terminating ack"),CeCosSocket::NOTIMEOUT)){
960
          TRACE(_T("Terminating ack=%d\n"),nAck);
961
        }
962
      } else {
963
        String strHostPort(CeCosSocket::HostPort(CeCosSocket::MyHostName(),m_nAuxPort));
964
 
965
        TRACE(_T("Using %s\n"),(LPCTSTR)strHostPort);
966
 
967
        if(m_pSock->sendString(strHostPort,_T("host:port"))){
968
 
969
          // This Boolean signifies that the serial<-->tcp/ip conversation is done.  It may be set
970
          // on completion of the ConnectSocketToSerial thread (which is why we pass it to runthread)
971
          // and also set by us to *cause* the thread to complete.
972
 
973
          bool bConnectSocketToSerialThreadDone=false; // Indication of termination of ConnectSocketToSerial thread
974
          m_bStopConnectSocketToSerial=false; // Used to tap ConnectSocketToSerial thread on the shoulder
975
 
976
          CeCosThreadUtils::RunThread(SConnectSocketToSerialThreadFunc,this,&bConnectSocketToSerialThreadDone,_T("SConnectSocketToSerialThreadFunc"));
977
 
978
          // Wait for either client or the ConnectSocketToSerial thread to finish.
979
          if(m_pSock->recv(&nAck,sizeof(int),_T("Terminating ack"),CeCosSocket::NOTIMEOUT,DerefBool,&bConnectSocketToSerialThreadDone)){
980
            TRACE(_T("Session terminated by request of client (%s)\n"),(LPCTSTR)Image((StatusType)nAck));
981
          } else if(0!=m_pSock->SocketError()){
982
            TRACE(_T("Session terminated by socket error - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
983
          }
984
          if(!bConnectSocketToSerialThreadDone){
985
            // Tap ConnectSocketToSerial thread on the shoulder
986
            TRACE(_T("Waiting for ConnectSocketToSerial thread to terminate...\n"));
987
            m_bStopConnectSocketToSerial=true;
988
            CeCosThreadUtils::WaitFor(bConnectSocketToSerialThreadDone);
989
          }
990
        }
991
      }
992
    }
993
  }
994
  delete this;
995
}
996
 
997
bool CeCosTest::send(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
998
{
999
  return m_pSock->send(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
1000
}
1001
 
1002
bool CeCosTest::recv(const void *pData,unsigned int nLength,LPCTSTR pszMsg,Duration dTimeout)
1003
{
1004
  return m_pSock->recv(pData,nLength,pszMsg,dTimeout,IsCancelled,this);
1005
}
1006
 
1007
void CeCosTest::Log(LPCTSTR  pszFormat, ...)
1008
{
1009
  va_list args;
1010
  va_start(args, pszFormat);
1011
  String str;
1012
  str.vFormat(pszFormat,args);
1013
  va_end(args);
1014
  LogString(str);
1015
}
1016
 
1017
void CeCosTest::LogString(LPCTSTR psz)
1018
{
1019
  if(*psz){
1020
    ENTERCRITICAL;
1021
    m_strOutput+=psz;
1022
    LEAVECRITICAL;
1023
    if(CeCosTrace::IsInteractive()){
1024
      CeCosTrace::Out(psz);
1025
    } else {
1026
      TRACE(_T("%s"),psz);
1027
    }
1028
  }
1029
}
1030
 
1031
bool CeCosTest::sendResult(Duration dTimeout)
1032
{
1033
  bool rc=
1034
    m_pSock->sendInteger(m_Status,_T("result"),dTimeout) &&
1035
    m_pSock->sendInteger(m_nDownloadTime,_T("result"),dTimeout) &&
1036
    m_pSock->sendInteger(m_nTotalTime,_T("result"),dTimeout) &&
1037
    m_pSock->sendInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
1038
    m_pSock->sendString (m_strOutput,_T("result"),dTimeout);
1039
  return rc;
1040
}
1041
 
1042
bool CeCosTest::recvResult(Duration dTimeout)
1043
{
1044
  String strOutput;
1045
  int nStatus=StatusTypeMax;
1046
  bool rc=
1047
    m_pSock->recvInteger(nStatus,_T("result"),dTimeout) &&
1048
    m_pSock->recvInteger(m_nDownloadTime,_T("result"),dTimeout) &&
1049
    m_pSock->recvInteger(m_nTotalTime,_T("result"),dTimeout) &&
1050
    m_pSock->recvInteger(m_nMaxInactiveTime,_T("result"),dTimeout) &&
1051
    m_pSock->recvString (strOutput,_T("result"),dTimeout);
1052
  m_Status=(StatusType)MIN(nStatus,StatusTypeMax);
1053
  LogString(strOutput);
1054
  return rc;
1055
}
1056
 
1057
// Return time used by inferior gdb process - CPU for sim, wallclock otherwise
1058
Time CeCosTest::InferiorTime() const
1059
{
1060
  if(*(m_pResource->Serial())){
1061
    return Now();
1062
  }
1063
  if(!m_psp){
1064
    return 0;
1065
  }
1066
  Time now=Now();
1067
  if(now-m_tPrevSample>1000){
1068
    m_tPrevSample=now;
1069
    m_tInferiorCpuTime=m_psp->CpuTime();
1070
  }
1071
  return m_tInferiorCpuTime;
1072
}
1073
 
1074
bool CeCosTest::CheckForTimeout()
1075
{
1076
  bool rc=(Cancelled!=Status());
1077
  if(TimeOut!=m_Status && DownloadTimeOut!=m_Status){
1078
    Time t=InferiorTime();
1079
    if(t){
1080
      // We have been able to measure the time
1081
      if(m_bDownloading){
1082
        m_nDownloadTime=MAX(m_nDownloadTime,Duration(InferiorTime()-m_tBase));
1083
        if(m_nDownloadTime>m_ep.DownloadTimeout()){
1084
          Log(_T("\n*** Timeout - download time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nDownloadTime),WF(m_ep.DownloadTimeout()));
1085
          rc=false;
1086
        }
1087
      } else {
1088
        m_nMaxInactiveTime=MAX(m_nMaxInactiveTime,Duration(InferiorTime()-m_tBase));
1089
        if (m_nMaxInactiveTime>m_ep.ActiveTimeout()) {
1090
          Log(_T("\n*** Timeout - inactive time ") WFS _T(" exceeds limit of ") WFS _T("\n"),WF(m_nMaxInactiveTime),WF(m_ep.ActiveTimeout()));
1091
          rc=false;
1092
        }
1093
      }
1094
    }
1095
    m_nTotalTime=Duration(Now()-m_tWallClock0);
1096
/*
1097
    if(m_nTotalTime>m_ep.ElapsedTimeout()){
1098
      Log(_T("\n*** Timeout - total time ") WFS _T(" exceeds limit of ") WFS _T("\n"),   WF(m_nTotalTime),WF(m_ep.ElapsedTimeout()));
1099
      rc=false;
1100
    }
1101
*/
1102
    if(!rc){
1103
      SetStatus(m_bDownloading?DownloadTimeOut:TimeOut);
1104
    }
1105
  }
1106
  return rc;
1107
}
1108
 
1109
// Convert a path to something a cygwin tool will understand.  Used when invoking -size and -gdb
1110
String CeCosTest::CygPath (LPCTSTR pszPath)
1111
{
1112
#ifdef __CYGWIN__
1113
    char buffer[MAX_PATH + 1];
1114
    long len = ::GetShortPathName (pszPath, NULL, 0);
1115
    if (len > 0) {
1116
        char shortpath [len + 1];
1117
        ::GetShortPathName (pszPath, shortpath, len + 1);
1118
        cygwin_conv_to_posix_path (shortpath, buffer);
1119
    } else {
1120
        cygwin_conv_to_posix_path (pszPath, buffer);
1121
    }
1122
    return buffer;
1123
#elif defined(_WIN32)
1124
#warning "native Win32 build does not support UNC file paths"
1125
  String str = "";
1126
  HKEY hKey = 0;
1127
  DWORD type;
1128
  BYTE value[256];
1129
  DWORD sz = sizeof(value);
1130
 
1131
  // look for the cygdrive prefix in the user's registry settings
1132
  if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Cygnus Solutions\\Cygwin\\mounts v2", 0, KEY_READ, &hKey)) {
1133
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, "cygdrive prefix", NULL, & type, value, & sz)) {
1134
      str = (const char*) value;
1135
    }
1136
    RegCloseKey(hKey);
1137
  }
1138
 
1139
  // if not yet found, look for the cygdrive prefix in the system registry settings
1140
  hKey = 0;
1141
  sz = sizeof(value);
1142
  if (str.empty() && (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Cygnus Solutions\\Cygwin\\mounts v2", 0, KEY_READ, &hKey))) {
1143
    if (ERROR_SUCCESS == RegQueryValueEx(hKey, "cygdrive prefix", NULL, & type, value, & sz)) {
1144
      str = (const char*) value;
1145
    }
1146
    RegCloseKey(hKey);
1147
  }
1148
 
1149
  int prefixlen = str.length();
1150
  TCHAR *buf=str.GetBuffer(prefixlen+1+MAX_PATH);
1151
  TCHAR *pszFname;
1152
  if(::GetFullPathName(pszPath,MAX_PATH,prefixlen+buf, &pszFname)){
1153
    GetShortPathName(prefixlen+buf,prefixlen+buf,MAX_PATH); // ignore errors
1154
    buf[prefixlen+1]=buf[prefixlen];
1155
    buf[prefixlen]=_TCHAR('/');
1156
    for(int i=prefixlen+2;buf[i];i++){
1157
      if(_TCHAR('\\')==buf[i]){
1158
        buf[i]=_TCHAR('/');
1159
      }
1160
    }
1161
    str.ReleaseBuffer();
1162
    return str;
1163
  } else {
1164
    str.ReleaseBuffer();
1165
    return pszPath;
1166
  }
1167
#endif
1168
  return pszPath;
1169
}
1170
 
1171
void CeCosTest::SetExecutable(LPCTSTR pszExecutable)
1172
{
1173
  m_strOutput=_T("");
1174
  if(pszExecutable){
1175
    m_strExecutable=pszExecutable;
1176
    if(m_ep.Platform()){
1177
      GetSizes();
1178
    } else {
1179
      ERROR(_T("Don't know how to get sizes of this platform type\n"));
1180
    }
1181
  } else {
1182
    m_strExecutable=_T("");
1183
  }
1184
}
1185
 
1186
// Calculate the sizes of the given file.  The target parameter is necessary in order to 
1187
// determine which -size executable to use to do the job.
1188
bool CeCosTest::GetSizes()
1189
{
1190
TRACE(_T("GetSizes %s\n"),(LPCTSTR)Executable());
1191
  bool rc=false;
1192
  m_nStrippedSize=m_nFileSize=0;
1193
  String strPrefix(m_ep.Platform()->Prefix());
1194
  if (strPrefix.length() > 0) strPrefix += _T("-");
1195
  struct _stat buf;
1196
  if(-1==_tstat(Executable(),&buf)){
1197
    Log(_T("%s does not exist\n"),(LPCTSTR)Executable());
1198
  } else {
1199
    m_nFileSize=buf.st_size;
1200
    const String strSizeCmd(String::SFormat(_T("%ssize %s"),(LPCTSTR)strPrefix,(LPCTSTR)CygPath(Executable())));
1201
    String strOut;
1202
    CSubprocess sp;
1203
    if(!sp.Run(strOut,strSizeCmd)){
1204
      Log(_T("Failed to run \"%s\" - %s\n"),(LPCTSTR)strSizeCmd,(LPCTSTR)sp.ErrorString());
1205
    } else {
1206
      const TCHAR *c=_tcschr(strOut,_TCHAR('\n'));
1207
      if(c){
1208
        c++;
1209
      }
1210
      int s1=0;
1211
      int s2=0;
1212
      if(c && 2==_stscanf(c,_T(" %d %d"),&s1,&s2)){
1213
        rc=true;
1214
        m_nStrippedSize=s1+s2;
1215
      }
1216
      TRACE(_T("GetSizes %s rc=%d file size=%d stripped size=%d\n"),(LPCTSTR)Executable(),rc,m_nFileSize,m_nStrippedSize);
1217
    }
1218
  }
1219
  return rc;
1220
}
1221
 
1222
void CeCosTest::SetTimeouts (Duration dActive,Duration dDownload/*,Duration dElapsed*/)
1223
{
1224
  m_ep.SetActiveTimeout  (dActive);
1225
  m_ep.SetDownloadTimeout(dDownload);
1226
/*
1227
  m_ep.SetElapsedTimeout (dElapsed);
1228
*/
1229
}
1230
 
1231
void CeCosTest::CloseSocket (){
1232
  delete m_pSock;
1233
  m_pSock=0;
1234
}
1235
 
1236
bool CeCosTest::AtPrompt()
1237
{
1238
  const String strPrompt(m_ep.Platform()->Prompt());
1239
  unsigned int nPromptLen=_tcslen(strPrompt);
1240
  return
1241
    nPromptLen>0 &&
1242
    m_strOutput.size()>=nPromptLen &&
1243
    0==_tcscmp((LPCTSTR)m_strOutput+m_strOutput.size()-nPromptLen,strPrompt);
1244
}
1245
 
1246
#ifdef _WIN32
1247
BOOL WINAPI HandlerRoutine(
1248
                           DWORD dwCtrlType   //  control signal type
1249
                           )
1250
{
1251
  dwCtrlType; // eliminate compiler warning
1252
  return TRUE;
1253
}
1254
#endif
1255
 
1256
 
1257
bool CeCosTest::InteractiveInferior(LPCTSTR pszHostPort,TCHAR **argv)
1258
{
1259
  bool rc=false;
1260
  if(_TCHAR('\0')!=*pszHostPort){
1261
    if(!CeCosSocket::IsLegalHostPort(pszHostPort)){
1262
      ERROR(_T("Illegal host:port '%s'\n"),pszHostPort);
1263
      return false;
1264
    } else {
1265
      m_strExecutionHostPort=pszHostPort;
1266
      Log(_T("Waiting to connect to %s...\n"),(LPCTSTR)m_strExecutionHostPort);
1267
    }
1268
  } else {
1269
    Log(_T("Waiting to connect to a server...\n"));
1270
  }
1271
 
1272
  ConnectForExecution();
1273
 
1274
  Log(_T("Connected to %s - waiting for target reset\n"),(LPCTSTR)m_strExecutionHostPort);
1275
  String strHostPort,strOutput;
1276
  // We read:
1277
  //     target ready indicator
1278
  //     any output so far
1279
  //     (if target ready) host:port
1280
  if(GetTargetReady(strHostPort)){
1281
    Log(_T("Use target remote %s\n"),(LPCTSTR)strHostPort);
1282
    String strInferior(m_ep.Platform()->Prefix());
1283
    strInferior+=_T("-gdb");
1284
#ifdef _WIN32
1285
    SetConsoleCtrlHandler(HandlerRoutine,TRUE);
1286
    int n=_tspawnvp(_P_WAIT,strInferior,argv);
1287
    if(-1==n){
1288
      Log(_T("Failed to spawn %s\n"),(LPCTSTR)strInferior);
1289
    } else {
1290
      rc=(0==n);
1291
    }
1292
    SetConsoleCtrlHandler(HandlerRoutine,FALSE);
1293
#else // UNIX
1294
 
1295
    int pid=fork();
1296
    switch(pid){
1297
    case -1:
1298
      _ftprintf(stderr,_T("fork failed\n"));
1299
      pid=0;
1300
      break;
1301
    case 0:
1302
      // Process is created (we're the child)
1303
      execvp(strInferior,argv);
1304
      Log(_T("Error invoking %s - %s\n"),(LPCTSTR)strInferior,strerror(errno));
1305
      exit(1);
1306
      break;
1307
    default:
1308
      // Process is created (we're the parent)
1309
      {
1310
        signal(SIGINT,SIG_IGN);
1311
        int stat;
1312
        waitpid(pid,&stat,0);
1313
        rc=(0==stat);
1314
        signal(SIGINT,SIG_DFL);
1315
      }
1316
      break;
1317
    }
1318
#endif
1319
    Log(_T("Inferior terminated\n"));
1320
    // Tell the server we're through
1321
    m_pSock->sendInteger(123,_T("Terminating ack"));
1322
  }
1323
  return rc;
1324
}
1325
 
1326
void CALLBACK CeCosTest::ResetLogFunc(void *pParam, LPCTSTR psz)
1327
{
1328
  CeCosTest *pTest=(CeCosTest *)pParam;
1329
  TRACE(_T("Send Target Ready indicator=2\n"));
1330
  pTest->m_pSock->sendInteger(2,_T("target ready indicator"));
1331
  TRACE(_T("Send %s\n"),psz);
1332
  pTest->m_pSock->sendString(psz,_T("output so far"));
1333
}
1334
 
1335
CeCosTest::ExecutionParameters::RequestType CeCosTest::ExecutionParameters::RequestTypeValue(LPCTSTR psz)
1336
{
1337
  int r;
1338
  for(r=0;r<RequestTypeMax;r++){
1339
    if(0==_tcsicmp(psz,arRequestImage[r])){
1340
      break;
1341
    }
1342
  }
1343
  return (RequestType)r;
1344
}
1345
 
1346
void CeCosTest::InferiorOutputFunc(LPCTSTR pszMsg)
1347
{
1348
  LogString(pszMsg);
1349
 
1350
  m_nOutputLen+=_tcslen(pszMsg);
1351
 
1352
  if(m_pspPipe){
1353
    m_pspPipe->Send(pszMsg);
1354
  }
1355
 
1356
  if(m_nOutputLen>20000){
1357
    LogString(_T("\n>>>> Infra FAIL\n*** too much output ***\n>>>>\n"));
1358
    SetStatus(Fail);
1359
    m_psp->Kill();
1360
  }
1361
 
1362
  m_tBase=InferiorTime(); // We are seeing life, so reset the clock for timeouts
1363
 
1364
  if(AtPrompt()){
1365
 
1366
    // gdb's output included one or more prompts
1367
    // Send another command along
1368
    if(m_nCmdIndex>=m_arstrInferiorCmds.size()){
1369
      // Nothing further to say to gdb - exit
1370
 
1371
      m_psp->Kill(); // case 3
1372
    } else {
1373
 
1374
      if(m_nCmdIndex>0 && 0==_tcscmp(_T("load"),m_arstrInferiorCmds[m_nCmdIndex-1])){
1375
        // load command was previous command - we are no longer downloading
1376
        m_bDownloading=false;
1377
      }
1378
 
1379
      String strCmd(m_arstrInferiorCmds[m_nCmdIndex++]);
1380
 
1381
      // If we can there is a GDB instruction to send to gdb, do it
1382
      String str;
1383
      if(GetDirective(_T("GDB:"),str,m_nLastGdbInst)){
1384
        strCmd=str;
1385
        m_nCmdIndex--; // undo increment above
1386
      }
1387
 
1388
      if(0==_tcscmp(_T("load"),strCmd)){
1389
        // load command issued - we are now "downloading"
1390
        m_bDownloading=true;
1391
      } else if(0==_tcscmp(_T("run"),strCmd) || 0==_tcscmp(_T("cont"),strCmd)){
1392
        SetStatus(NoResult);
1393
      }
1394
 
1395
      strCmd+=_TCHAR('\n');
1396
      LogString(strCmd);
1397
      m_psp->Send(strCmd);
1398
 
1399
    }
1400
  }
1401
 
1402
  // If there is a EXEC instruction to process, obey it
1403
  String strCmd;
1404
  while(GetDirective(_T("EXEC:"),strCmd,m_nLastExecInst)){
1405
    CSubprocess *pExecsp=new CSubprocess;
1406
    pExecsp->SetPath(m_strPath);
1407
    if(!pExecsp->Run(AppendFunc,this,(LPCTSTR)strCmd,false)){
1408
      Log(_T("%%%% Failed to create process '%s'\n"),(LPCTSTR)strCmd);
1409
      delete pExecsp;
1410
    } else {
1411
      m_arpExecsp.push_back(pExecsp);
1412
    }
1413
  }
1414
 
1415
  // If there is a PIPE instruction to process, obey it
1416
  while(GetDirective(_T("PIPE:"),strCmd,m_nLastPipeInst)){
1417
    if(m_pspPipe){
1418
      Log(_T("%%%% Two PIPE commands are a no-no\n"));
1419
    } else {
1420
      m_pspPipe=new CSubprocess;
1421
      m_pspPipe->SetPath(m_strPath);
1422
 
1423
      if(!m_pspPipe->Run(AppendFunc,this,(LPCTSTR)strCmd,false)){
1424
        Log(_T("%%%% Failed to create process '%s'\n"),(LPCTSTR)strCmd);
1425
        delete m_pspPipe;
1426
        m_pspPipe=0;
1427
      } else {
1428
        // Send what we read have so far
1429
        m_pspPipe->Send(m_strOutput);
1430
      }
1431
    }
1432
  }
1433
 
1434
  while(GetDirective(_T("TIMEOUT:"),strCmd,m_nLastTimeoutInst)){
1435
    int n=_ttoi(strCmd);
1436
    if(n){
1437
      SetTimeouts(n); // second parameter is download timeout, which is now irrelevant
1438
    } else {
1439
      Log(_T("%%%% Illegal timeout specified: %s\n"),(LPCTSTR)strCmd);
1440
    }
1441
  }
1442
}
1443
 
1444
void CeCosTest::RunInferior(LPCTSTR pszCmdline)
1445
{
1446
  m_psp=new CSubprocess;
1447
  m_psp->SetContinuationFunc(SCheckForTimeout,this);
1448
  try {
1449
    m_nMaxInactiveTime=0;
1450
    m_nTotalTime=0;
1451
    m_nDownloadTime=0;
1452
    m_nOutputLen=0;
1453
    m_bDownloading=false;
1454
 
1455
    // Decide on the baseline status - NotStarted if there is a download element, NoResult otherwise.
1456
    m_Status=NoResult;
1457
    for(unsigned int i=0;i<m_arstrInferiorCmds.size();i++){
1458
      if(0==_tcscmp(_T("run"),m_arstrInferiorCmds[i]) || 0==_tcscmp(_T("cont"),m_arstrInferiorCmds[i])){
1459
        m_Status=NotStarted;
1460
        break;
1461
      }
1462
    }
1463
    TRACE(_T("Status <- %s\n"),(LPCTSTR)Image(m_Status));
1464
 
1465
    m_tPrevSample=0; // force an initial reading
1466
    m_tInferiorCpuTime=0;
1467
 
1468
    m_tBase=m_tBase0=InferiorTime(); // Returns either Now() or nothing
1469
    m_tWallClock0=Now();
1470
 
1471
    m_nCmdIndex=0;
1472
 
1473
    TRACE(_T("RunGDB()\n"));
1474
 
1475
    m_nLastGdbInst=m_nLastExecInst=m_nLastTimeoutInst=m_nLastPipeInst=0;
1476
    m_psp->SetPath(m_strPath);
1477
    if(m_psp->Run(SInferiorOutputFunc,this,pszCmdline,true)){
1478
 
1479
      if(m_pspPipe){
1480
        m_pspPipe->Send(_T("\n"));
1481
        m_pspPipe->CloseInput();
1482
        if(m_pspPipe->Wait(5000)){
1483
          // OK the pipe process terminated.
1484
          int rc=m_pspPipe->GetExitCode();
1485
          if(0!=rc){
1486
            Log(_T("%%%% Pipe process returned rc=%d\n"),rc);
1487
            SetStatus(Fail);
1488
          }
1489
        } else {
1490
          LogString(_T("%%%% Pipe process would not complete\n"));
1491
        }
1492
      }
1493
 
1494
      AnalyzeOutput();
1495
 
1496
    } else {
1497
      Log(_T("Failed to run \"%s\" - %s\n"),pszCmdline,(LPCTSTR)m_psp->ErrorString());
1498
    }
1499
  }
1500
  catch(...){
1501
    ERROR(_T("!!! Exception caught in RunInferior()\n"));
1502
  }
1503
  delete m_psp; // will cause process to be killed as necessary and completion to be waited for
1504
  m_psp=NULL;
1505
  for(int i=0;i<(signed)m_arpExecsp.size();i++){
1506
    delete (CSubprocess *)m_arpExecsp[i]; // ditto
1507
  }
1508
  m_arpExecsp.clear();
1509
  TRACE(_T("Exiting RunInferior()\n"));
1510
}
1511
 
1512
void CeCosTest::AnalyzeOutput()
1513
{
1514
  // This test is pulled out to allow ser_filter to simulate a test failure
1515
  if(OutputContains(_T("FAIL:"))){
1516
    SetStatus(Fail);
1517
  }
1518
 
1519
  if(OutputContains(_T("EXIT:"))||OutputContains(_T("NOTAPPLICABLE:"))){
1520
    static LPCTSTR arpszKeepAlive[]={_T("FAIL:"),_T("NOTAPPLICABLE:"), _T("PASS:")};
1521
    static const StatusType arStatus[] ={Fail, Inapplicable, Pass};
1522
    for(unsigned int i=0;i<sizeof arpszKeepAlive/sizeof arpszKeepAlive[0];i++){
1523
      if(OutputContains(arpszKeepAlive[i])){
1524
        TRACE(_T("DriveInferior: saw '%s'\n"),arpszKeepAlive[i]);
1525
        SetStatus(arStatus[i]); // Do not break!
1526
      }
1527
    }
1528
  }
1529
 
1530
  // Certain output spells failure...
1531
  if(OutputContains(_T("cyg_assert_fail ("))){
1532
    SetStatus(AssertFail);
1533
  } else {
1534
    static LPCTSTR arpszSignals[]={_T("SIGBUS"), _T("SIGSEGV"), _T("SIGILL"), _T("SIGFPE"), _T("SIGSYS"), _T("SIGTRAP")};
1535
    for(unsigned int i=0;i<sizeof arpszSignals/sizeof arpszSignals[0];i++){
1536
      String str1,str2;
1537
      str1.Format(_T("signal %s"),arpszSignals[i]);
1538
      str2.Format(_T("handle %s nostop"),arpszSignals[i]);
1539
      if(OutputContains(str1)&&!OutputContains(str2)){
1540
        SetStatus(Fail);
1541
        break;
1542
      }
1543
    }
1544
  }
1545
 
1546
  int nIndex=0;
1547
  String str;
1548
  while(GetDirective(_T("EXPECT:"),str,nIndex)){
1549
    // s1 is the pointer to the text following the expect - that to be tested
1550
    LPCTSTR s1=(LPCTSTR)m_strOutput+nIndex;
1551
    while (_istspace(*s1)){
1552
      s1++;
1553
    }
1554
    // whereas s2 is the pointer to the text in the expect string (what we are expecting)
1555
    LPCTSTR s2=(LPCTSTR)str;
1556
    while(*s2){
1557
      if(*s2!=*s1){
1558
        Log(_T("EXPECT:<> failure - expected '%s' saw '%s'\n"),(LPCTSTR)str,(LPCTSTR)m_strOutput+nIndex);
1559
        SetStatus(Fail);
1560
        break;
1561
      }
1562
      s1++;
1563
      s2++;
1564
    }
1565
  }
1566
}
1567
 
1568
bool CeCosTest::ExecutionParameters::FromStr(LPCTSTR psz)
1569
{
1570
  String str1,str2,str3,str4,str5;
1571
  int nUseFilter,nUnused2,nUnused3;
1572
  int nLen=_tcslen(psz);
1573
  _stscanf(psz,_T("%s %s %d %d %d %d %d %d %d %d %s %s %s"),
1574
    str1.GetBuffer(1+nLen),
1575
    str2.GetBuffer(1+nLen),
1576
    &m_nActiveTimeout,
1577
    &m_nDownloadTimeout,
1578
    &m_nUnused1,
1579
    &m_nUnused2,
1580
    &m_nUnused3,
1581
    &nUseFilter,
1582
    &nUnused2,
1583
    &nUnused3,
1584
    str3.GetBuffer(1+nLen),
1585
    str4.GetBuffer(1+nLen),
1586
    str5.GetBuffer(1+nLen)
1587
    );
1588
  m_bUseFilter=(0!=nUseFilter);
1589
  m_bUnused2=(0!=nUnused2);
1590
  m_bUnused3=(0!=nUnused3);
1591
  str1.ReleaseBuffer();
1592
  str2.ReleaseBuffer();
1593
  str3.ReleaseBuffer();
1594
  str4.ReleaseBuffer();
1595
  str5.ReleaseBuffer();
1596
  m_Target=str1;
1597
  int r;
1598
  for(r=0;r<RequestTypeMax;r++){
1599
    if(0==_tcscmp(arRequestImage[r],str2)){
1600
      break;
1601
    }
1602
  }
1603
  m_Request=(RequestType)r;
1604
  return CeCosTestPlatform::IsValid(m_Target);
1605
}
1606
 
1607
CeCosTest::ExecutionParameters::ExecutionParameters (RequestType r,
1608
                                                     LPCTSTR  Target,
1609
                                                     Duration    nActiveTimeout/*=NOTIMEOUT*/,
1610
                                                     Duration    nDownloadTimeout/*=NOTIMEOUT*/):
1611
  m_bUseFilter(true),
1612
  m_Target(Target),
1613
  m_nActiveTimeout(nActiveTimeout),
1614
  m_nDownloadTimeout(nDownloadTimeout),
1615
  m_Request(r),
1616
  m_nUnused1(0),
1617
  m_nUnused2(0),
1618
  m_nUnused3(0),
1619
  m_bUnused2(false),
1620
  m_bUnused3(false)
1621
{
1622
}
1623
 
1624
String CeCosTest::ExecutionParameters::Image() const
1625
{
1626
  String str;
1627
  str.Format(_T("%s %s %d %d %d %d %d %d %d %d"),(LPCTSTR)PlatformName(),(LPCTSTR)Image(Request()),
1628
    ActiveTimeout(),DownloadTimeout(),
1629
    m_nUnused1,
1630
    m_nUnused2,
1631
    m_nUnused3,
1632
    m_bUseFilter,
1633
    m_bUnused2,
1634
    m_bUnused3);
1635
  return str;
1636
}
1637
 
1638
bool CeCosTest::GetTargetReady(String &strHostPort)
1639
{
1640
  bool rc=false;
1641
  int nTargetReady;
1642
  do{
1643
    if(!m_pSock->recvInteger(nTargetReady,_T("Target ready"),120*1000)){
1644
      Log(_T("Failed to read target ready indicator from server - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
1645
      break;
1646
    }
1647
    switch(nTargetReady){
1648
    case 0:
1649
      LogString(_T("Failed to reset target"));
1650
      break;
1651
    case 1:
1652
      if(m_pSock->recvString(strHostPort, _T("host:port"))){
1653
        TRACE(_T("Instructed to use %s\n"),(LPCTSTR)strHostPort);
1654
        rc=true;
1655
      } else {
1656
        Log(_T("Failed to read host:port - %s\n"),(LPCTSTR)m_pSock->SocketErrString());
1657
      }
1658
      break;
1659
    case 2:
1660
      {
1661
        String strOutput;
1662
        if(m_pSock->recvString(strOutput, _T("output"))){
1663
          LogString(strOutput);
1664
        } else {
1665
          Log(_T("Failed to read output\n"),(LPCTSTR)m_pSock->SocketErrString());
1666
          return false;
1667
        }
1668
      }
1669
      break;
1670
    }
1671
  } while(2==nTargetReady);
1672
  return rc;
1673
}
1674
 
1675
 
1676
CeCosTest::ServerStatus CeCosTest::ServerStatusValue(LPCTSTR psz)
1677
{
1678
  int s;
1679
  for(s=0;s<ServerStatusMax;s++){
1680
    if(0==_tcsicmp(psz,arServerStatusImage[s])){
1681
      break;
1682
    }
1683
  }
1684
  return (ServerStatus)s;
1685
 
1686
}
1687
 
1688
// Gets a directive from the test output (like EXEC:)
1689
bool CeCosTest::GetDirective(LPCTSTR pszDirective, String &str, int &nIndex)
1690
{
1691
  bool rc=false;
1692
  ENTERCRITICAL;
1693
  LPCTSTR pszOutput=(LPCTSTR)m_strOutput;
1694
  LPCTSTR pc=_tcsstr(pszOutput+nIndex,pszDirective);
1695
  if(pc){
1696
 
1697
    pc+=_tcslen(pszDirective); // Now after the final character (':') of the directive
1698
    if(_TCHAR('<')==*pc){
1699
 
1700
      pc++;
1701
 
1702
      // Extract the argument
1703
      str=_T("");
1704
      while(*pc){
1705
        // Process escapes: FIXME more escapes?
1706
        TCHAR c=*pc;
1707
        if(_TCHAR('\\')==c){
1708
          switch(pc[1]){
1709
            case _TCHAR('t'):
1710
              c=_TCHAR('\t');
1711
              break;
1712
            case _TCHAR('n'):
1713
              c=_TCHAR('\n');
1714
              break;
1715
            case _TCHAR('\0'):
1716
              pc--; // avoid grief
1717
              break;
1718
            default:
1719
              c=pc[1];
1720
              break;
1721
          }
1722
          pc++;
1723
        } else if (_TCHAR('>')==c) {
1724
          nIndex=pc+1-pszOutput;
1725
          rc=true;
1726
          break;
1727
        } else if (_TCHAR('\n')==c) {
1728
          nIndex=pc+1-pszOutput;
1729
          Log(_T("%%%% Unterminated directive: %s"),(LPCTSTR)str);
1730
          break;
1731
        }
1732
        str+=c;
1733
        pc++;
1734
      }
1735
    }
1736
  }
1737
  LEAVECRITICAL;
1738
  return rc;
1739
}
1740
 
1741
void CeCosTest::GetInferiorCommands(StringArray &arstrInferiorCmds)
1742
{
1743
  arstrInferiorCmds.clear();
1744
 
1745
  // Construct commands for gdb.  The commands may be found (semicolon-separated) in the target info:
1746
  const String strInferiorCmds(m_ep.Platform()->GdbCmds());
1747
  StringArray ar;
1748
  int nCmds=strInferiorCmds.Chop(ar,_TCHAR(';'),false);
1749
  for(int i=0;i<nCmds;i++){
1750
    // Into each command must be substituted:
1751
    // Baud rate (%b)  
1752
    // Port      (%p)  This will be a serial port (e.g. COM1) or a socket connection (e.g.aloo:8000) depending on circumstances.
1753
    // and escapes must be dealt with.
1754
    String strCmd;
1755
    for(const TCHAR *pc=ar[i];*pc;pc++){
1756
      switch(*pc){
1757
        // Process escapes: FIXME more escapes?
1758
        case _TCHAR('\\'):
1759
          switch(pc[1]){
1760
            case _TCHAR('t'):
1761
              strCmd+=_TCHAR('\t');
1762
              pc++;
1763
              continue;
1764
            case _TCHAR('n'):
1765
              strCmd+=_TCHAR('\n');
1766
              pc++;
1767
              continue;
1768
            case _TCHAR('\0'):
1769
              continue;
1770
            default:
1771
              break;
1772
          }
1773
          break;
1774
        case _TCHAR('%'):
1775
          switch(pc[1]){
1776
            case _TCHAR('%'):
1777
              strCmd+=_TCHAR('%');
1778
              pc++;
1779
              break;
1780
            case _TCHAR('b'):
1781
              if(0==m_pResource->Baud()){
1782
                goto NextCmd; // Suppress output of this command if there is no baud rate to output
1783
              }
1784
              strCmd+=String::SFormat(_T("%d"),m_pResource->Baud());
1785
              pc++;
1786
              continue;
1787
            case _TCHAR('p'):
1788
              if(_TCHAR('\0')==*(m_pResource->Serial())){
1789
                goto NextCmd; // Suppress output of this command if there is no serial port
1790
              }
1791
              strCmd+=m_pResource->Serial();
1792
              pc++;
1793
              continue;
1794
            case _TCHAR('\0'):
1795
              continue;
1796
            default:
1797
              break;
1798
          }
1799
          break;
1800
        default:
1801
          break;
1802
      }
1803
      strCmd+=*pc;
1804
    }
1805
    arstrInferiorCmds.push_back(strCmd);
1806
NextCmd:
1807
    ;
1808
  }
1809
  return;
1810
}
1811
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.