Example #1
0
Error MachException::PortInfo::Save(task_t task) {
  Error error;
  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));

  if (log)
    log->Printf("MachException::PortInfo::%s(task = 0x%4.4x)", __FUNCTION__,
                task);

  // Be careful to be able to have debugserver built on a newer OS than what
  // it is currently running on by being able to start with all exceptions
  // and back off to just what is supported on the current system
  mask = LLDB_EXC_MASK;

  count = (sizeof(ports) / sizeof(ports[0]));
  auto mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports,
                                             behaviors, flavors);
  if (mach_err)
    error.SetError(mach_err, eErrorTypeMachKernel);

  if (log) {
    if (error.Success()) {
      log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask = "
                  "0x%x, maskCnt => %u, ports, behaviors, flavors)",
                  task, mask, count);
    } else {
      log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask = 0x%x, "
                  "maskCnt => %u, ports, behaviors, flavors) error: %u (%s)",
                  task, mask, count, error.GetError(), error.AsCString());
    }
  }

  if ((error.GetError() == KERN_INVALID_ARGUMENT) &&
      (mask != PREV_EXC_MASK_ALL)) {
    mask = PREV_EXC_MASK_ALL;
    count = (sizeof(ports) / sizeof(ports[0]));
    mach_err = ::task_get_exception_ports(task, mask, masks, &count, ports,
                                          behaviors, flavors);
    error.SetError(mach_err, eErrorTypeMachKernel);
    if (log) {
      if (error.Success()) {
        log->Printf("::task_get_exception_ports(task = 0x%4.4x, "
                    "mask = 0x%x, maskCnt => %u, ports, behaviors, "
                    "flavors)",
                    task, mask, count);
      } else {
        log->Printf("::task_get_exception_ports(task = 0x%4.4x, mask = "
                    "0x%x, maskCnt => %u, ports, behaviors, flavors) "
                    "error: %u (%s)",
                    task, mask, count, error.GetError(), error.AsCString());
      }
    }
  }
  if (error.Fail()) {
    mask = 0;
    count = 0;
  }
  return error;
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
{
    packet.SetFilePos(::strlen("vFile:unlink:"));
    std::string path;
    packet.GetHexByteString(path);
    Error error = Host::Unlink(path.c_str());
    StreamString response;
    response.Printf("F%u,%u", error.GetError(), error.GetError());
    return SendPacketNoLock(response.GetData(), response.GetSize());
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_vFile_unlink(
    StringExtractorGDBRemote &packet) {
  packet.SetFilePos(::strlen("vFile:unlink:"));
  std::string path;
  packet.GetHexByteString(path);
  Error error = FileSystem::Unlink(FileSpec{path, true});
  StreamString response;
  response.Printf("F%u,%u", error.GetError(), error.GetError());
  return SendPacketNoLock(response.GetString());
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_vFile_symlink(
    StringExtractorGDBRemote &packet) {
  packet.SetFilePos(::strlen("vFile:symlink:"));
  std::string dst, src;
  packet.GetHexByteStringTerminatedBy(dst, ',');
  packet.GetChar(); // Skip ',' char
  packet.GetHexByteString(src);
  Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
  StreamString response;
  response.Printf("F%u,%u", error.GetError(), error.GetError());
  return SendPacketNoLock(response.GetString());
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
{
    packet.SetFilePos(::strlen("vFile:symlink:"));
    std::string dst, src;
    packet.GetHexByteStringTerminatedBy(dst, ',');
    packet.GetChar(); // Skip ',' char
    packet.GetHexByteString(src);
    Error error = Host::Symlink(src.c_str(), dst.c_str());
    StreamString response;
    response.Printf("F%u,%u", error.GetError(), error.GetError());
    return SendPacketNoLock(response.GetData(), response.GetSize());
}
Example #6
0
size_t
ProcessWindows::DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size, Error &error)
{
    llvm::sys::ScopedLock lock(m_mutex);
    WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory attempting to write %u bytes into address 0x%I64x", size, vm_addr);

    if (!m_session_data)
    {
        WINERR_IFANY(WINDOWS_LOG_MEMORY, "DoWriteMemory cannot write, there is no active debugger connection.");
        return 0;
    }

    HostProcess process = m_session_data->m_debugger->GetProcess();
    void *addr = reinterpret_cast<void *>(vm_addr);
    SIZE_T bytes_written = 0;
    lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
    if (WriteProcessMemory(handle, addr, buf, size, &bytes_written))
        FlushInstructionCache(handle, addr, bytes_written);
    else
    {
        error.SetError(GetLastError(), eErrorTypeWin32);
        WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoWriteMemory failed with error code %u", error.GetError());
    }
    return bytes_written;
}
Example #7
0
Error PipePosix::CreateWithUniqueName(llvm::StringRef prefix,
                                      bool child_process_inherit,
                                      llvm::SmallVectorImpl<char> &name) {
  llvm::SmallString<PATH_MAX> named_pipe_path;
  llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str());
  FileSpec tmpdir_file_spec;
  tmpdir_file_spec.Clear();
  if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) {
    tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
  } else {
    tmpdir_file_spec.AppendPathComponent("/tmp");
    tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str());
  }

  // It's possible that another process creates the target path after we've
  // verified it's available but before we create it, in which case we
  // should try again.
  Error error;
  do {
    llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath(),
                                    named_pipe_path);
    error = CreateNew(named_pipe_path, child_process_inherit);
  } while (error.GetError() == EEXIST);

  if (error.Success())
    name = named_pipe_path;
  return error;
}
Error PlatformRemoteGDBServer::Unlink(const FileSpec &file_spec) {
  Error error = m_gdb_client.Unlink(file_spec);
  Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
  if (log)
    log->Printf("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)",
                file_spec.GetCString(), error.GetError(), error.AsCString());
  return error;
}
Example #9
0
size_t
ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
{
    Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION));
    if (log)
        log->Printf("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", static_cast<void *>(this),
                    static_cast<const void *>(src), static_cast<uint64_t>(src_len));

    if (!IsConnected())
    {
        if (error_ptr)
            error_ptr->SetErrorString("not connected");
        status = eConnectionStatusNoConnection;
        return 0;
    }

    Error error;

    size_t bytes_sent = src_len;
    error = m_write_sp->Write(src, bytes_sent);

    if (log)
    {
        log->Printf("%p ConnectionFileDescriptor::Write(fd = %" PRIu64 ", src = %p, src_len = %" PRIu64 ") => %" PRIu64 " (error = %s)",
                    static_cast<void *>(this), static_cast<uint64_t>(m_write_sp->GetWaitableHandle()), static_cast<const void *>(src),
                    static_cast<uint64_t>(src_len), static_cast<uint64_t>(bytes_sent), error.AsCString());
    }

    if (error_ptr)
        *error_ptr = error;

    if (error.Fail())
    {
        switch (error.GetError())
        {
            case EAGAIN:
            case EINTR:
                status = eConnectionStatusSuccess;
                return 0;

            case ECONNRESET: // The connection is closed by the peer during a read attempt on a socket.
            case ENOTCONN:   // A read is attempted on an unconnected socket.
                status = eConnectionStatusLostConnection;
                break; // Break to close....

            default:
                status = eConnectionStatusError;
                break; // Break to close....
        }

        return 0;
    }

    status = eConnectionStatusSuccess;
    return bytes_sent;
}
Error
PlatformRemoteGDBServer::MakeDirectory(const FileSpec &file_spec, uint32_t mode)
{
    Error error = m_gdb_client.MakeDirectory(file_spec, mode);
    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
    if (log)
        log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)",
                file_spec.GetCString(), mode, error.GetError(), error.AsCString());
    return error;
}
Error
PlatformRemoteGDBServer::SetFilePermissions(const FileSpec &file_spec,
                                            uint32_t file_permissions)
{
    Error error = m_gdb_client.SetFilePermissions(file_spec, file_permissions);
    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
    if (log)
        log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)",
                file_spec.GetCString(), file_permissions, error.GetError(), error.AsCString());
    return error;
}
Error
PlatformRemoteGDBServer::CreateSymlink(const FileSpec &src,    // The name of the link is in src
                                       const FileSpec &dst)    // The symlink points to dst
{
    Error error = m_gdb_client.CreateSymlink(src, dst);
    Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM);
    if (log)
        log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)",
                src.GetCString(), dst.GetCString(), error.GetError(), error.AsCString());
    return error;
}
Example #13
0
void
ProcessWindows::OnDebuggerError(const Error &error, uint32_t type)
{
    llvm::sys::ScopedLock lock(m_mutex);

    if (m_session_data->m_initial_stop_received)
    {
        // This happened while debugging.  Do we shutdown the debugging session, try to continue,
        // or do something else?
        WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred during debugging.  Unexpected behavior may result.  %s",
                     error.GetError(), error.AsCString());
    }
    else
    {
        // If we haven't actually launched the process yet, this was an error launching the
        // process.  Set the internal error and signal the initial stop event so that the DoLaunch
        // method wakes up and returns a failure.
        m_session_data->m_launch_error = error;
        ::SetEvent(m_session_data->m_initial_stop_event);
        WINERR_IFALL(WINDOWS_LOG_PROCESS, "Error %u occurred launching the process before the initial stop.  %s",
                     error.GetError(), error.AsCString());
        return;
    }
}
Example #14
0
Error
ProcessWindowsLive::GetMemoryRegionInfo(lldb::addr_t vm_addr, MemoryRegionInfo &info)
{
    Error error;
    llvm::sys::ScopedLock lock(m_mutex);

    if (!m_session_data)
    {
        error.SetErrorString("GetMemoryRegionInfo called with no debugging session.");
        WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString());
        return error;
    }

    HostProcess process = m_session_data->m_debugger->GetProcess();
    lldb::process_t handle = process.GetNativeProcess().GetSystemHandle();
    if (handle == nullptr || handle == LLDB_INVALID_PROCESS)
    {
        error.SetErrorString("GetMemoryRegionInfo called with an invalid target process.");
        WINERR_IFALL(WINDOWS_LOG_MEMORY, error.AsCString());
        return error;
    }

    WINLOG_IFALL(WINDOWS_LOG_MEMORY, "GetMemoryRegionInfo getting info for address 0x%I64x", vm_addr);

    void *addr = reinterpret_cast<void *>(vm_addr);
    MEMORY_BASIC_INFORMATION mem_info = {0};
    SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info));
    if (result == 0)
    {
        error.SetError(::GetLastError(), eErrorTypeWin32);
        WINERR_IFALL(WINDOWS_LOG_MEMORY,
                     "VirtualQueryEx returned error %u while getting memory region info for address 0x%I64x",
                     error.GetError(), vm_addr);
        return error;
    }
    const bool readable = IsPageReadable(mem_info.Protect);
    const bool executable = IsPageExecutable(mem_info.Protect);
    const bool writable = IsPageWritable(mem_info.Protect);
    info.SetReadable(readable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
    info.SetExecutable(executable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);
    info.SetWritable(writable ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo);

    error.SetError(::GetLastError(), eErrorTypeWin32);
    WINLOGV_IFALL(WINDOWS_LOG_MEMORY, "Memory region info for address 0x%I64u: readable=%s, executable=%s, writable=%s",
                  BOOL_STR(readable), BOOL_STR(executable), BOOL_STR(writable));
    return error;
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_vFile_Mode(
    StringExtractorGDBRemote &packet) {
  packet.SetFilePos(::strlen("vFile:mode:"));
  std::string path;
  packet.GetHexByteString(path);
  if (!path.empty()) {
    Error error;
    const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error);
    StreamString response;
    response.Printf("F%u", mode);
    if (mode == 0 || error.Fail())
      response.Printf(",%i", (int)error.GetError());
    return SendPacketNoLock(response.GetString());
  }
  return SendErrorResponse(23);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
{
    packet.SetFilePos(::strlen("qPlatform_mkdir:"));
    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
    if (packet.GetChar() == ',')
    {
        std::string path;
        packet.GetHexByteString(path);
        Error error = Host::MakeDirectory(path.c_str(),mode);
        if (error.Success())
            return SendPacketNoLock ("OK", 2);
        else
            return SendErrorResponse(error.GetError());
    }
    return SendErrorResponse(20);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir(
    StringExtractorGDBRemote &packet) {
  packet.SetFilePos(::strlen("qPlatform_mkdir:"));
  mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
  if (packet.GetChar() == ',') {
    std::string path;
    packet.GetHexByteString(path);
    Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode);

    StreamGDBRemote response;
    response.Printf("F%u", error.GetError());

    return SendPacketNoLock(response.GetString());
  }
  return SendErrorResponse(20);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
{
    packet.SetFilePos(::strlen("qPlatform_chmod:"));

    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
    if (packet.GetChar() == ',')
    {
        std::string path;
        packet.GetHexByteString(path);
        Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode);

        StreamGDBRemote response;
        response.Printf("F%u", error.GetError());

        return SendPacketNoLock(response.GetData(), response.GetSize());
    }
    return SendErrorResponse(19);
}
Example #19
0
Error
ProcessWindows::DoHalt(bool &caused_stop)
{
    Error error;
    StateType state = GetPrivateState();
    if (state == eStateStopped)
        caused_stop = false;
    else
    {
        llvm::sys::ScopedLock lock(m_mutex);
        caused_stop = ::DebugBreakProcess(m_session_data->m_debugger->GetProcess().GetNativeProcess().GetSystemHandle());
        if (!caused_stop)
        {
            error.SetError(::GetLastError(), eErrorTypeWin32);
            WINERR_IFALL(WINDOWS_LOG_PROCESS, "DoHalt called DebugBreakProcess, but it failed with error %u",
                         error.GetError());
        }
    }
    return error;
}
Example #20
0
Error MachException::PortInfo::Restore(task_t task) {
  Error error;

  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));

  if (log)
    log->Printf("MachException::PortInfo::Restore(task = 0x%4.4x)", task);

  uint32_t i = 0;
  if (count > 0) {
    for (i = 0; i < count; i++) {
      auto mach_err = ::task_set_exception_ports(task, masks[i], ports[i],
                                                 behaviors[i], flavors[i]);
      if (mach_err)
        error.SetError(mach_err, eErrorTypeMachKernel);
      if (log) {
        if (error.Success()) {
          log->Printf("::task_set_exception_ports(task = 0x%4.4x, "
                      "exception_mask = 0x%8.8x, new_port = 0x%4.4x, "
                      "behavior = 0x%8.8x, new_flavor = 0x%8.8x)",
                      task, masks[i], ports[i], behaviors[i], flavors[i]);
        } else {
          log->Printf("::task_set_exception_ports(task = 0x%4.4x, "
                      "exception_mask = 0x%8.8x, new_port = 0x%4.4x, "
                      "behavior = 0x%8.8x, new_flavor = 0x%8.8x): "
                      "error %u (%s)",
                      task, masks[i], ports[i], behaviors[i], flavors[i],
                      error.GetError(), error.AsCString());
        }
      }

      // Bail if we encounter any errors
      if (error.Fail())
        break;
    }
  }

  count = 0;
  return error;
}
Example #21
0
size_t
ProcessWindows::DoReadMemory(lldb::addr_t vm_addr,
                             void *buf,
                             size_t size,
                             Error &error)
{
    llvm::sys::ScopedLock lock(m_mutex);

    if (!m_session_data)
        return 0;

    WINLOG_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory attempting to read %u bytes from address 0x%I64x", size, vm_addr);

    HostProcess process = m_session_data->m_debugger->GetProcess();
    void *addr = reinterpret_cast<void *>(vm_addr);
    SIZE_T bytes_read = 0;
    if (!ReadProcessMemory(process.GetNativeProcess().GetSystemHandle(), addr, buf, size, &bytes_read))
    {
        error.SetError(GetLastError(), eErrorTypeWin32);
        WINERR_IFALL(WINDOWS_LOG_MEMORY, "DoReadMemory failed with error code %u", error.GetError());
    }
    return bytes_read;
}
Example #22
0
void SendError( int priority, const char* module_name, const Error& error )
{
    SendErrorText( priority, module_name, error.GetError());
}
Example #23
0
//----------------------------------------------------------------------
// The file descriptor FD is assumed to already be opened as read only
// and the STAT structure is assumed to a valid pointer and already
// containing valid data from a call to stat().
//
// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
// as possible.
//
// RETURNS
//  Number of bytes mapped starting from the requested offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, 
                                                  off_t offset, 
                                                  size_t length,
                                                  bool writeable,
                                                  bool fd_is_file)
{
    Clear();
    if (fd >= 0)
    {
        struct stat stat;
        if (::fstat(fd, &stat) == 0)
        {
            if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
            {
                const size_t max_bytes_available = stat.st_size - offset;
                if (length == SIZE_MAX)
                {
                    length = max_bytes_available;
                }
                else if (length > max_bytes_available)
                {
                    // Cap the length if too much data was requested
                    length = max_bytes_available;
                }

                if (length > 0)
                {
                    int prot = PROT_READ;
                    if (writeable)
                        prot |= PROT_WRITE;

                    int flags = MAP_PRIVATE;
                    if (fd_is_file)
                        flags |= MAP_FILE;

                    m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);

                    if (m_mmap_addr == (void*)-1)
                    {
                        Error error;
                        error.SetErrorToErrno ();
                        if (error.GetError() == EINVAL)
                        {
                            // We may still have a shot at memory mapping if we align things correctly
                            size_t page_offset = offset % Host::GetPageSize();
                            if (page_offset != 0)
                            {
                                m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
                                if (m_mmap_addr == (void*)-1)
                                {
                                    // Failed to map file
                                    m_mmap_addr = NULL;
                                }
                                else if (m_mmap_addr != NULL)
                                {
                                    // We recovered and were able to memory map
                                    // after we aligned things to page boundaries

                                    // Save the actual mmap'ed size
                                    m_mmap_size = length + page_offset;
                                    // Our data is at an offset into the the mapped data
                                    m_data = m_mmap_addr + page_offset;
                                    // Our pretend size is the size that was requestd
                                    m_size = length;
                                }
                            }
                        }
                        if (error.GetError() == ENOMEM)
                        {
                           error.SetErrorStringWithFormat("could not allocate %lld bytes of memory to mmap in file", (uint64_t) length);
                        }
                    }
                    else
                    {
                        // We were able to map the requested data in one chunk
                        // where our mmap and actual data are the same.
                        m_mmap_size = length;
                        m_data = m_mmap_addr;
                        m_size = length;
                    }
                }
            }
        }
    }
    return GetByteSize ();
}
Example #24
0
ConnectionStatus
ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
{
    // Don't need to take the mutex here separately since we are only called from Read.  If we
    // ever get used more generally we will need to lock here as well.
    
    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
    if (log)
        log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
    struct timeval *tv_ptr;
    struct timeval tv;
    if (timeout_usec == UINT32_MAX)
    {
        // Infinite wait...
        tv_ptr = NULL;
    }
    else
    {
        TimeValue time_value;
        time_value.OffsetWithMicroSeconds (timeout_usec);
        tv = time_value.GetAsTimeVal();
        tv_ptr = &tv;
    }

    while (m_fd_recv >= 0)
    {
        fd_set read_fds;
        FD_ZERO (&read_fds);
        FD_SET (m_fd_recv, &read_fds);
        if (m_pipe_read != -1)
            FD_SET (m_pipe_read, &read_fds);
        int nfds = std::max<int>(m_fd_recv, m_pipe_read) + 1;
        
        Error error;


        if (log)
            log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
                        this, nfds, m_fd_recv, tv_ptr);

        const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
        if (num_set_fds < 0)
            error.SetErrorToErrno();
        else
            error.Clear();

        if (log)
            log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
                        this, nfds, m_fd_recv, tv_ptr, num_set_fds, error.AsCString());

        if (error_ptr)
            *error_ptr = error;

        if (error.Fail())
        {
            switch (error.GetError())
            {
            case EBADF:     // One of the descriptor sets specified an invalid descriptor.
                return eConnectionStatusLostConnection;

            case EINVAL:    // The specified time limit is invalid. One of its components is negative or too large.
            default:        // Other unknown error
                return eConnectionStatusError;

            case EAGAIN:    // The kernel was (perhaps temporarily) unable to
                            // allocate the requested number of file descriptors,
                            // or we have non-blocking IO
            case EINTR:     // A signal was delivered before the time limit
                            // expired and before any of the selected events
                            // occurred.
                break;      // Lets keep reading to until we timeout
            }
        }
        else if (num_set_fds == 0)
        {
            return eConnectionStatusTimedOut;
        }
        else if (num_set_fds > 0)
        {
            if (m_pipe_read != -1 && FD_ISSET(m_pipe_read, &read_fds))
            {
                // We got a command to exit.  Read the data from that pipe:
                char buffer[16];
                ssize_t bytes_read;
                
                do
                {
                    bytes_read = ::read (m_pipe_read, buffer, sizeof(buffer));
                } while (bytes_read < 0 && errno == EINTR);
                assert (bytes_read == 1 && buffer[0] == 'q');
                
                if (log)
                    log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
                                this, (int) bytes_read, buffer);

                return eConnectionStatusEndOfFile;
            }
            else
                return eConnectionStatusSuccess;
        }
    }

    if (error_ptr)
        error_ptr->SetErrorString("not connected");
    return eConnectionStatusLostConnection;
}
Example #25
0
 bool
 DoExecute (Args& command, CommandReturnObject &result)
 {
     const size_t argc = command.GetArgumentCount();
     if (argc == 0)
     {
         if (!m_command_byte.GetOptionValue().OptionWasSet())
         {
             result.AppendError ("the --command option must be set to a valid command byte");
             result.SetStatus (eReturnStatusFailed);
         }
         else
         {
             const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0);
             if (command_byte > 0 && command_byte <= UINT8_MAX)
             {
                 ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
                 if (process)
                 {
                     const StateType state = process->GetState();
                     
                     if (StateIsStoppedState (state, true))
                     {
                         std::vector<uint8_t> payload_bytes;
                         const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue();
                         if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0])
                         {
                             StringExtractor extractor(ascii_hex_bytes_cstr);
                             const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size();
                             if (ascii_hex_bytes_cstr_len & 1)
                             {
                                 result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr);
                                 result.SetStatus (eReturnStatusFailed);
                                 return false;
                             }
                             payload_bytes.resize(ascii_hex_bytes_cstr_len/2);
                             if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size())
                             {
                                 result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr);
                                 result.SetStatus (eReturnStatusFailed);
                                 return false;
                             }
                         }
                         Error error;
                         DataExtractor reply;
                         process->GetCommunication().SendRawRequest (command_byte,
                                                                     payload_bytes.empty() ? NULL : payload_bytes.data(),
                                                                     payload_bytes.size(),
                                                                     reply,
                                                                     error);
                         
                         if (error.Success())
                         {
                             // Copy the binary bytes into a hex ASCII string for the result
                             StreamString packet;
                             packet.PutBytesAsRawHex8(reply.GetDataStart(),
                                                      reply.GetByteSize(),
                                                      lldb::endian::InlHostByteOrder(),
                                                      lldb::endian::InlHostByteOrder());
                             result.AppendMessage(packet.GetString().c_str());
                             result.SetStatus (eReturnStatusSuccessFinishResult);
                             return true;
                         }
                         else
                         {
                             const char *error_cstr = error.AsCString();
                             if (error_cstr && error_cstr[0])
                                 result.AppendError (error_cstr);
                             else
                                 result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError());
                             result.SetStatus (eReturnStatusFailed);
                             return false;
                         }
                     }
                     else
                     {
                         result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state));
                         result.SetStatus (eReturnStatusFailed);
                     }
                 }
                 else
                 {
                     result.AppendError ("invalid process");
                     result.SetStatus (eReturnStatusFailed);
                 }
             }
             else
             {
                 result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte);
                 result.SetStatus (eReturnStatusFailed);
             }
         }
     }
     else
     {
         result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str());
         result.SetStatus (eReturnStatusFailed);
     }
     return false;
 }
Example #26
0
size_t
ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
{
    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
    if (log)
        log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %llu)", this, src, (uint64_t)src_len);

    if (!IsConnected ())
    {
        if (error_ptr)
            error_ptr->SetErrorString("not connected");
        status = eConnectionStatusNoConnection;
        return 0;
    }


    Error error;

    ssize_t bytes_sent = 0;

    switch (m_fd_send_type)
    {
        case eFDTypeFile:       // Other FD requireing read/write
            do
            {
                bytes_sent = ::write (m_fd_send, src, src_len);
            } while (bytes_sent < 0 && errno == EINTR);
            break;
            
        case eFDTypeSocket:     // Socket requiring send/recv
            do
            {
                bytes_sent = ::send (m_fd_send, src, src_len, 0);
            } while (bytes_sent < 0 && errno == EINTR);
            break;
            
        case eFDTypeSocketUDP:  // Unconnected UDP socket requiring sendto/recvfrom
            assert (m_udp_send_sockaddr.GetFamily() != 0);
            do
            {
                bytes_sent = ::sendto (m_fd_send, 
                                       src, 
                                       src_len, 
                                       0, 
                                       m_udp_send_sockaddr, 
                                       m_udp_send_sockaddr.GetLength());
            } while (bytes_sent < 0 && errno == EINTR);
            break;
    }

    if (bytes_sent < 0)
        error.SetErrorToErrno ();
    else
        error.Clear ();

    if (log)
    {
        switch (m_fd_send_type)
        {
            case eFDTypeFile:       // Other FD requireing read/write
                log->Printf ("%p ConnectionFileDescriptor::Write()  ::write (fd = %i, src = %p, src_len = %llu) => %lli (error = %s)",
                             this, 
                             m_fd_send, 
                             src, 
                             (uint64_t)src_len,
                             (int64_t)bytes_sent,
                             error.AsCString());
                break;
                
            case eFDTypeSocket:     // Socket requiring send/recv
                log->Printf ("%p ConnectionFileDescriptor::Write()  ::send (socket = %i, src = %p, src_len = %llu, flags = 0) => %lli (error = %s)",
                             this, 
                             m_fd_send, 
                             src, 
                             (uint64_t)src_len,
                             (int64_t)bytes_sent,
                             error.AsCString());
                break;
                
            case eFDTypeSocketUDP:  // Unconnected UDP socket requiring sendto/recvfrom
                log->Printf ("%p ConnectionFileDescriptor::Write()  ::sendto (socket = %i, src = %p, src_len = %llu, flags = 0) => %lli (error = %s)",
                             this, 
                             m_fd_send, 
                             src, 
                             (uint64_t)src_len,
                             (int64_t)bytes_sent, 
                             error.AsCString());
                break;
        }
    }

    if (error_ptr)
        *error_ptr = error;

    if (error.Fail())
    {
        switch (error.GetError())
        {
        case EAGAIN:
        case EINTR:
            status = eConnectionStatusSuccess;
            return 0;

        case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
        case ENOTCONN:  // A read is attempted on an unconnected socket.
            status = eConnectionStatusLostConnection;
            break;  // Break to close....

        default:
            status = eConnectionStatusError;
            break;  // Break to close....
        }

        return 0;
    }

    status = eConnectionStatusSuccess;
    return bytes_sent;
}
Example #27
0
size_t
ConnectionFileDescriptor::Read (void *dst, 
                                size_t dst_len, 
                                uint32_t timeout_usec,
                                ConnectionStatus &status, 
                                Error *error_ptr)
{
    LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
    if (log)
        log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %llu)...",
                     this, m_fd_recv, dst, (uint64_t)dst_len);

    Mutex::Locker locker;
    bool got_lock = locker.TryLock (m_mutex);
    if (!got_lock)
    {
        if (log)
            log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
                     this);
        if (error_ptr)
            error_ptr->SetErrorString ("failed to get the connection lock for read.");
            
        status = eConnectionStatusTimedOut;
        return 0;
    }
    else if (m_shutting_down)
        return eConnectionStatusError;
    
    ssize_t bytes_read = 0;

    status = BytesAvailable (timeout_usec, error_ptr);
    if (status == eConnectionStatusSuccess)
    {
        do
        {
            bytes_read = ::read (m_fd_recv, dst, dst_len);
        } while (bytes_read < 0 && errno == EINTR);
    }

    if (status != eConnectionStatusSuccess)
        return 0;

    Error error;
    if (bytes_read == 0)
    {
        error.Clear(); // End-of-file.  Do not automatically close; pass along for the end-of-file handlers.
        status = eConnectionStatusEndOfFile;
    }
    else if (bytes_read < 0)
    {
        error.SetErrorToErrno();
    }
    else
    {
        error.Clear();
    }

    if (log)
        log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %llu) => %lli, error = %s",
                     this, 
                     m_fd_recv, 
                     dst, 
                     (uint64_t)dst_len,
                     (int64_t)bytes_read,
                     error.AsCString());

    if (error_ptr)
        *error_ptr = error;

    if (error.Fail())
    {
        uint32_t error_value = error.GetError();
        switch (error_value)
        {
        case EAGAIN:    // The file was marked for non-blocking I/O, and no data were ready to be read.
            if (m_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP)
                status = eConnectionStatusTimedOut;
            else
                status = eConnectionStatusSuccess;
            return 0;

        case EFAULT:    // Buf points outside the allocated address space.
        case EINTR:     // A read from a slow device was interrupted before any data arrived by the delivery of a signal.
        case EINVAL:    // The pointer associated with fildes was negative.
        case EIO:       // An I/O error occurred while reading from the file system.
                        // The process group is orphaned.
                        // The file is a regular file, nbyte is greater than 0,
                        // the starting position is before the end-of-file, and
                        // the starting position is greater than or equal to the
                        // offset maximum established for the open file
                        // descriptor associated with fildes.
        case EISDIR:    // An attempt is made to read a directory.
        case ENOBUFS:   // An attempt to allocate a memory buffer fails.
        case ENOMEM:    // Insufficient memory is available.
            status = eConnectionStatusError;
            break;  // Break to close....

        case ENOENT:    // no such file or directory
        case EBADF:     // fildes is not a valid file or socket descriptor open for reading.
        case ENXIO:     // An action is requested of a device that does not exist..
                        // A requested action cannot be performed by the device.
        case ECONNRESET:// The connection is closed by the peer during a read attempt on a socket.
        case ENOTCONN:  // A read is attempted on an unconnected socket.
            status = eConnectionStatusLostConnection;
            break;  // Break to close....

        case ETIMEDOUT: // A transmission timeout occurs during a read attempt on a socket.
            status = eConnectionStatusTimedOut;
            return 0;
        }

        //Disconnect (NULL);
        return 0;
    }
    return bytes_read;
}
Example #28
0
lldb::thread_result_t
Communication::ReadThread (lldb::thread_arg_t p)
{
    Communication *comm = (Communication *)p;

    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));

    if (log)
        log->Printf ("%p Communication::ReadThread () thread starting...", p);

    uint8_t buf[1024];

    Error error;
    ConnectionStatus status = eConnectionStatusSuccess;
    bool done = false;
    while (!done && comm->m_read_thread_enabled)
    {
        size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), 5 * TimeValue::MicroSecPerSec, status, &error);
        if (bytes_read > 0)
            comm->AppendBytesToCache (buf, bytes_read, true, status);
        else if ((bytes_read == 0)
                && status == eConnectionStatusEndOfFile)
        {
            if (comm->GetCloseOnEOF ())
                comm->Disconnect ();
            comm->AppendBytesToCache (buf, bytes_read, true, status);
        }

        switch (status)
        {
        case eConnectionStatusSuccess:
            break;

        case eConnectionStatusEndOfFile:
            done = true;
            break;
        case eConnectionStatusError:            // Check GetError() for details
            if (error.GetType() == eErrorTypePOSIX && error.GetError() == EIO)
            {
                // EIO on a pipe is usually caused by remote shutdown
                comm->Disconnect ();
                done = true;
            }
            if (log)
                error.LogIfError (log,
                                  "%p Communication::ReadFromConnection () => status = %s",
                                  p,
                                  Communication::ConnectionStatusAsCString (status));
            break;
        case eConnectionStatusInterrupted:      // Synchronization signal from SynchronizeWithReadThread()
            // The connection returns eConnectionStatusInterrupted only when there is no
            // input pending to be read, so we can signal that.
            comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
            break;
        case eConnectionStatusNoConnection:     // No connection
        case eConnectionStatusLostConnection:   // Lost connection while connected to a valid connection
            done = true;
            LLVM_FALLTHROUGH;
        case eConnectionStatusTimedOut:         // Request timed out
            if (log)
                error.LogIfError (log,
                                  "%p Communication::ReadFromConnection () => status = %s",
                                  p,
                                  Communication::ConnectionStatusAsCString (status));
            break;
        }
    }
    log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
    if (log)
        log->Printf ("%p Communication::ReadThread () thread exiting...", p);

    comm->m_read_thread_did_exit = true;
    // Let clients know that this thread is exiting
    comm->BroadcastEvent (eBroadcastBitNoMorePendingInput);
    comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
    return NULL;
}
ConnectionStatus
ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
{
    // Don't need to take the mutex here separately since we are only called from Read.  If we
    // ever get used more generally we will need to lock here as well.

    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_CONNECTION));
    if (log)
        log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)",
                    static_cast<void*>(this), timeout_usec);

    struct timeval *tv_ptr;
    struct timeval tv;
    if (timeout_usec == UINT32_MAX)
    {
        // Inifinite wait...
        tv_ptr = nullptr;
    }
    else
    {
        TimeValue time_value;
        time_value.OffsetWithMicroSeconds (timeout_usec);
        tv.tv_sec = time_value.seconds();
        tv.tv_usec = time_value.microseconds();
        tv_ptr = &tv;
    }

    // Make a copy of the file descriptors to make sure we don't
    // have another thread change these values out from under us
    // and cause problems in the loop below where like in FS_SET()
    const IOObject::WaitableHandle handle = m_read_sp->GetWaitableHandle();
    const int pipe_fd = m_pipe.GetReadFileDescriptor();

    if (handle != IOObject::kInvalidHandleValue)
    {
#if defined(_MSC_VER)
        // select() won't accept pipes on Windows.  The entire Windows codepath needs to be
        // converted over to using WaitForMultipleObjects and event HANDLEs, but for now at least
        // this will allow ::select() to not return an error.
        const bool have_pipe_fd = false;
#else
        const bool have_pipe_fd = pipe_fd >= 0;
#if !defined(__APPLE__)
        assert (handle < FD_SETSIZE);
        if (have_pipe_fd)
            assert (pipe_fd < FD_SETSIZE);
#endif
#endif
        while (handle == m_read_sp->GetWaitableHandle())
        {
            const int nfds = std::max<int>(handle, pipe_fd) + 1;
#if defined(__APPLE__)
            llvm::SmallVector<fd_set, 1> read_fds;
            read_fds.resize((nfds/FD_SETSIZE) + 1);
            for (size_t i=0; i<read_fds.size(); ++i)
                FD_ZERO (&read_fds[i]);
            // FD_SET doesn't bounds check, it just happily walks off the end
            // but we have taken care of making the extra storage with our
            // SmallVector of fd_set objects
#else
            fd_set read_fds;
            FD_ZERO (&read_fds);
#endif
            FD_SET (handle, FD_SET_DATA(read_fds));
            if (have_pipe_fd)
                FD_SET (pipe_fd, FD_SET_DATA(read_fds));

            Error error;

            if (log)
            {
                if (have_pipe_fd)
                    log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
                                static_cast<void*>(this), nfds, handle, pipe_fd,
                                static_cast<void*>(tv_ptr));
                else
                    log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
                                static_cast<void*>(this), nfds, handle,
                                static_cast<void*>(tv_ptr));
            }

            const int num_set_fds = ::select (nfds, FD_SET_DATA(read_fds), NULL, NULL, tv_ptr);
            if (num_set_fds < 0)
                error.SetErrorToErrno();
            else
                error.Clear();

            if (log)
            {
                if (have_pipe_fd)
                    log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
                                static_cast<void*>(this), nfds, handle,
                                pipe_fd, static_cast<void*>(tv_ptr), num_set_fds,
                                error.AsCString());
                else
                    log->Printf("%p ConnectionFileDescriptor::BytesAvailable()  ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
                                static_cast<void*>(this), nfds, handle,
                                static_cast<void*>(tv_ptr), num_set_fds,
                                error.AsCString());
            }

            if (error_ptr)
                *error_ptr = error;

            if (error.Fail())
            {
                switch (error.GetError())
                {
                    case EBADF:     // One of the descriptor sets specified an invalid descriptor.
                        return eConnectionStatusLostConnection;

                    case EINVAL:    // The specified time limit is invalid. One of its components is negative or too large.
                    default:        // Other unknown error
                        return eConnectionStatusError;

                    case EAGAIN:    // The kernel was (perhaps temporarily) unable to
                        // allocate the requested number of file descriptors,
                        // or we have non-blocking IO
                    case EINTR:     // A signal was delivered before the time limit
                        // expired and before any of the selected events
                        // occurred.
                        break;      // Lets keep reading to until we timeout
                }
            }
            else if (num_set_fds == 0)
            {
                return eConnectionStatusTimedOut;
            }
            else if (num_set_fds > 0)
            {
                if (FD_ISSET(handle, FD_SET_DATA(read_fds)))
                    return eConnectionStatusSuccess;
                if (have_pipe_fd && FD_ISSET(pipe_fd, FD_SET_DATA(read_fds)))
                {
                    // We got a command to exit.  Read the data from that pipe:
                    char buffer[16];
                    ssize_t bytes_read;

                    do
                    {
                        bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
                    } while (bytes_read < 0 && errno == EINTR);
                    
                    switch (buffer[0])
                    {
                    case 'q':
                        if (log)
                            log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
                                        static_cast<void*>(this),
                                        static_cast<int>(bytes_read), buffer);
                        return eConnectionStatusEndOfFile;
                    case 'i':
                        // Interrupt the current read
                        return eConnectionStatusInterrupted;
                    }
                }
            }
        }
    }

    if (error_ptr)
        error_ptr->SetErrorString("not connected");
    return eConnectionStatusLostConnection;
}
Example #30
0
//----------------------------------------------------------------------
// The file descriptor FD is assumed to already be opened as read only
// and the STAT structure is assumed to a valid pointer and already
// containing valid data from a call to stat().
//
// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
// as possible.
//
// RETURNS
//  Number of bytes mapped starting from the requested offset.
//----------------------------------------------------------------------
size_t
DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd, 
                                                  lldb::offset_t offset, 
                                                  size_t length,
                                                  bool writeable,
                                                  bool fd_is_file)
{
    Clear();
    if (fd >= 0)
    {
        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
        if (log)
        {
            log->Printf("DataBufferMemoryMap::MemoryMapFromFileDescriptor(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
                        fd,
                        offset,
                        (uint64_t)length,
                        writeable,
                        fd_is_file);
        }
#ifdef _WIN32
        HANDLE handle = (HANDLE)_get_osfhandle(fd);
        DWORD file_size_low, file_size_high;
        file_size_low = GetFileSize(handle, &file_size_high);
        const lldb::offset_t file_size = llvm::Make_64(file_size_high, file_size_low);
        const lldb::offset_t max_bytes_available = file_size - offset;
        const size_t max_bytes_mappable = (size_t)std::min<lldb::offset_t>(SIZE_MAX, max_bytes_available);
        if (length == SIZE_MAX || length > max_bytes_mappable)
        {
            // Cap the length if too much data was requested
            length = max_bytes_mappable;
        }

        if (length > 0)
        {
            HANDLE fileMapping = CreateFileMapping(handle, NULL, writeable ? PAGE_READWRITE : PAGE_READONLY, file_size_high, file_size_low, NULL);
            if (fileMapping != NULL)
            {
                if (win32memmapalignment == 0) LoadWin32MemMapAlignment();
                lldb::offset_t realoffset = offset;
                lldb::offset_t delta = 0;
                if (realoffset % win32memmapalignment != 0) {
                  realoffset = realoffset / win32memmapalignment * win32memmapalignment;
                  delta = offset - realoffset;
	            }

                LPVOID data = MapViewOfFile(fileMapping, writeable ? FILE_MAP_WRITE : FILE_MAP_READ, 0, realoffset, length + delta);
                m_mmap_addr = (uint8_t *)data;
                if (!data) {
                  Error error; 
                  error.SetErrorToErrno ();
                } else {
                  m_data = m_mmap_addr + delta;
                  m_size = length;
                }
                CloseHandle(fileMapping);
            }
        }
#else
        struct stat stat;
        if (::fstat(fd, &stat) == 0)
        {
            if (S_ISREG(stat.st_mode) &&
                (stat.st_size > static_cast<off_t>(offset)))
            {
                const size_t max_bytes_available = stat.st_size - offset;
                if (length == SIZE_MAX)
                {
                    length = max_bytes_available;
                }
                else if (length > max_bytes_available)
                {
                    // Cap the length if too much data was requested
                    length = max_bytes_available;
                }

                if (length > 0)
                {
                    int prot = PROT_READ;
                    if (writeable)
                        prot |= PROT_WRITE;

                    int flags = MAP_PRIVATE;
                    if (fd_is_file)
                        flags |= MAP_FILE;

                    m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
                    Error error;

                    if (m_mmap_addr == (void*)-1)
                    {
                        error.SetErrorToErrno ();
                        if (error.GetError() == EINVAL)
                        {
                            // We may still have a shot at memory mapping if we align things correctly
                            size_t page_offset = offset % Host::GetPageSize();
                            if (page_offset != 0)
                            {
                                m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
                                if (m_mmap_addr == (void*)-1)
                                {
                                    // Failed to map file
                                    m_mmap_addr = NULL;
                                }
                                else if (m_mmap_addr != NULL)
                                {
                                    // We recovered and were able to memory map
                                    // after we aligned things to page boundaries

                                    // Save the actual mmap'ed size
                                    m_mmap_size = length + page_offset;
                                    // Our data is at an offset into the the mapped data
                                    m_data = m_mmap_addr + page_offset;
                                    // Our pretend size is the size that was requestd
                                    m_size = length;
                                }
                            }
                        }
                        if (error.GetError() == ENOMEM)
                        {
                           error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
                        }
                    }
                    else
                    {
                        // We were able to map the requested data in one chunk
                        // where our mmap and actual data are the same.
                        m_mmap_size = length;
                        m_data = m_mmap_addr;
                        m_size = length;
                    }
                    
                    if (log)
                    {
                        log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %" PRIu64 ", error = %s",
                                    m_mmap_addr, (uint64_t)m_mmap_size, error.AsCString());
                    }
                }
            }
        }
#endif
    }
    return GetByteSize ();
}