pkgsrc-WIP-changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lldb-git: Add upstream patch for NetBSD core(5) files



Module Name:	pkgsrc-wip
Committed By:	Kamil Rytarowski <n54%gmx.com@localhost>
Pushed By:	kamil
Date:		Thu Apr 27 19:01:15 2017 +0200
Changeset:	5cfc746ab823870d31de4d1276f27caf2cd61c02

Modified Files:
	lldb-git/distinfo
Added Files:
	lldb-git/patches/patch-source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp
	lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.cpp
	lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.h

Log Message:
lldb-git: Add upstream patch for NetBSD core(5) files

This repo tracks:
Correct handling NetBSD core(5) files with threads
https://reviews.llvm.org/D32149

Sponsored by <The NetBSD Foundation>

To see a diff of this commit:
https://wip.pkgsrc.org/cgi-bin/gitweb.cgi?p=pkgsrc-wip.git;a=commitdiff;h=5cfc746ab823870d31de4d1276f27caf2cd61c02

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

diffstat:
 lldb-git/distinfo                                  |   3 +
 ...source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp |  77 +++++
 ...rce_Plugins_Process_elf-core_ProcessElfCore.cpp | 316 +++++++++++++++++++++
 ...ource_Plugins_Process_elf-core_ProcessElfCore.h |  23 ++
 4 files changed, 419 insertions(+)

diffs:
diff --git a/lldb-git/distinfo b/lldb-git/distinfo
index 7931384fd5..6675c1d21f 100644
--- a/lldb-git/distinfo
+++ b/lldb-git/distinfo
@@ -12,3 +12,6 @@ Size (libcxx-3.6.2.src.tar.xz) = 944020 bytes
 SHA1 (llvm-3.6.2.src.tar.xz) = 7a00257eb2bc9431e4c77c3a36b033072c54bc7e
 RMD160 (llvm-3.6.2.src.tar.xz) = 521cbc5fe2925ea3c6e90c7a31f752a04045c972
 Size (llvm-3.6.2.src.tar.xz) = 12802380 bytes
+SHA1 (patch-source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp) = d7d43c20b34068a5f535b8eeb1af2dc87c2b3175
+SHA1 (patch-source_Plugins_Process_elf-core_ProcessElfCore.cpp) = 602f857b411871583e05e9f6113e8768bfdc6098
+SHA1 (patch-source_Plugins_Process_elf-core_ProcessElfCore.h) = 5754bcca237decc7ef8519c54a34840b1869d476
diff --git a/lldb-git/patches/patch-source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp b/lldb-git/patches/patch-source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp
new file mode 100644
index 0000000000..4c4d038dc4
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_ObjectFile_ELF_ObjectFileELF.cpp
@@ -0,0 +1,77 @@
+$NetBSD$
+
+--- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp.orig	2017-04-27 16:58:55.405029614 +0000
++++ source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+@@ -52,6 +52,7 @@ namespace {
+ const char *const LLDB_NT_OWNER_FREEBSD = "FreeBSD";
+ const char *const LLDB_NT_OWNER_GNU = "GNU";
+ const char *const LLDB_NT_OWNER_NETBSD = "NetBSD";
++const char *const LLDB_NT_OWNER_NETBSDCORE = "NetBSD-CORE";
+ const char *const LLDB_NT_OWNER_OPENBSD = "OpenBSD";
+ const char *const LLDB_NT_OWNER_CSR = "csr";
+ const char *const LLDB_NT_OWNER_ANDROID = "Android";
+@@ -67,8 +68,10 @@ const elf_word LLDB_NT_GNU_ABI_SIZE = 16
+ 
+ const elf_word LLDB_NT_GNU_BUILD_ID_TAG = 0x03;
+ 
+-const elf_word LLDB_NT_NETBSD_ABI_TAG = 0x01;
+-const elf_word LLDB_NT_NETBSD_ABI_SIZE = 4;
++const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_TAG = 1;
++const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_DESCSZ = 4;
++const elf_word LLDB_NT_NETBSD_NT_NETBSD_IDENT_NAMESZ = 7;
++const elf_word LLDB_NT_NETBSD_NT_PROCINFO = 1;
+ 
+ // GNU ABI note OS constants
+ const elf_word LLDB_NT_GNU_ABI_OS_LINUX = 0x00;
+@@ -1370,25 +1373,41 @@ ObjectFileELF::RefineModuleDetailsFromNo
+         // The note.n_name == LLDB_NT_OWNER_GNU is valid for Linux platform
+         arch_spec.GetTriple().setOS(llvm::Triple::OSType::Linux);
+     }
+-    // Process NetBSD ELF notes.
++    // Process NetBSD ELF executables and shared libraries
+     else if ((note.n_name == LLDB_NT_OWNER_NETBSD) &&
+-             (note.n_type == LLDB_NT_NETBSD_ABI_TAG) &&
+-             (note.n_descsz == LLDB_NT_NETBSD_ABI_SIZE)) {
+-      // Pull out the min version info.
++             (note.n_type == LLDB_NT_NETBSD_NT_NETBSD_IDENT_TAG) &&
++             (note.n_descsz == LLDB_NT_NETBSD_NT_NETBSD_IDENT_DESCSZ) &&
++             (note.n_namesz == LLDB_NT_NETBSD_NT_NETBSD_IDENT_NAMESZ)) {
++      // Pull out the version info
+       uint32_t version_info;
+       if (data.GetU32(&offset, &version_info, 1) == nullptr) {
+         error.SetErrorString("failed to read NetBSD ABI note payload");
+         return error;
+       }
+-
++      // Convert the version info into a major/minor/patch number.
++      //     #define __NetBSD_Version__ MMmmrrpp00
++      //
++      //     M = major version
++      //     m = minor version; a minor number of 99 indicates current.
++      //     r = 0 (since NetBSD 3.0 not used)
++      //     p = patchlevel
++      const uint32_t version_major = version_info / 100000000;
++      const uint32_t version_minor = (version_info % 100000000) / 1000000;
++      const uint32_t version_patch = (version_info % 10000) / 100;
++      char os_name[32];
++      snprintf(os_name, sizeof(os_name),
++               "netbsd%" PRIu32 ".%" PRIu32 ".%" PRIu32, version_major,
++               version_minor, version_patch);
++      // Set the elf OS version to NetBSD.  Also clear the vendor.
++      arch_spec.GetTriple().setOSName(os_name);
++      arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
++    }
++    // Process NetBSD ELF core(5) notes
++    else if ((note.n_name == LLDB_NT_OWNER_NETBSDCORE) &&
++             (note.n_type == LLDB_NT_NETBSD_NT_PROCINFO)) {
+       // Set the elf OS version to NetBSD.  Also clear the vendor.
+       arch_spec.GetTriple().setOS(llvm::Triple::OSType::NetBSD);
+       arch_spec.GetTriple().setVendor(llvm::Triple::VendorType::UnknownVendor);
+-
+-      if (log)
+-        log->Printf(
+-            "ObjectFileELF::%s detected NetBSD, min version constant %" PRIu32,
+-            __FUNCTION__, version_info);
+     }
+     // Process OpenBSD ELF notes.
+     else if (note.n_name == LLDB_NT_OWNER_OPENBSD) {
diff --git a/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.cpp b/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.cpp
new file mode 100644
index 0000000000..aab844509e
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.cpp
@@ -0,0 +1,316 @@
+$NetBSD$
+
+--- source/Plugins/Process/elf-core/ProcessElfCore.cpp.orig	2017-04-27 16:58:55.433629177 +0000
++++ source/Plugins/Process/elf-core/ProcessElfCore.cpp
+@@ -27,6 +27,7 @@
+ #include "lldb/Utility/DataBufferLLVM.h"
+ #include "lldb/Utility/Log.h"
+ 
++#include "llvm/ADT/StringRef.h"
+ #include "llvm/Support/ELF.h"
+ #include "llvm/Support/Threading.h"
+ 
+@@ -458,9 +459,42 @@ enum {
+ 
+ namespace NETBSD {
+ 
+-enum { NT_PROCINFO = 1, NT_AUXV, NT_AMD64_REGS = 33, NT_AMD64_FPREGS = 35 };
++enum { NT_PROCINFO = 1, NT_AUXV = 2 };
++
++/* Size in bytes */
++enum { NT_PROCINFO_SIZE = 160 };
++
++/* Size in bytes */
++enum {
++NT_PROCINFO_CPI_VERSION_SIZE = 4,
++NT_PROCINFO_CPI_CPISIZE_SIZE = 4,
++NT_PROCINFO_CPI_SIGNO_SIZE = 4,
++NT_PROCINFO_CPI_SIGCODE_SIZE = 4,
++NT_PROCINFO_CPI_SIGPEND_SIZE = 16,
++NT_PROCINFO_CPI_SIGMASK_SIZE = 16,
++NT_PROCINFO_CPI_SIGIGNORE_SIZE = 16,
++NT_PROCINFO_CPI_SIGCATCH_SIZE = 16,
++NT_PROCINFO_CPI_PID_SIZE = 4,
++NT_PROCINFO_CPI_PPID_SIZE = 4,
++NT_PROCINFO_CPI_PGRP_SIZE = 4,
++NT_PROCINFO_CPI_SID_SIZE = 4,
++NT_PROCINFO_CPI_RUID_SIZE = 4,
++NT_PROCINFO_CPI_EUID_SIZE = 4,
++NT_PROCINFO_CPI_SVUID_SIZE = 4,
++NT_PROCINFO_CPI_RGID_SIZE = 4,
++NT_PROCINFO_CPI_EGID_SIZE = 4,
++NT_PROCINFO_CPI_SVGID_SIZE = 4,
++NT_PROCINFO_CPI_NLWPS_SIZE = 4,
++NT_PROCINFO_CPI_NAME_SIZE = 32,
++NT_PROCINFO_CPI_SIGLWP_SIZE = 4,
++};
++
++namespace AMD64 {
++enum { NT_REGS = 33, NT_FPREGS = 35 };
+ }
+ 
++} // namespace NETBSD
++
+ // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
+ static void ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
+                                  ArchSpec &arch) {
+@@ -497,15 +531,43 @@ static void ParseFreeBSDThrMisc(ThreadDa
+   thread_data.name = data.GetCStr(&offset, 20);
+ }
+ 
+-static void ParseNetBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
++static Error ParseNetBSDProcInfo(DataExtractor &data, uint32_t &cpi_nlwps,
++                                 uint32_t &cpi_signo, uint32_t &cpi_siglwp) {
+   lldb::offset_t offset = 0;
+ 
+-  int version = data.GetU32(&offset);
++  uint32_t version = data.GetU32(&offset);
+   if (version != 1)
+-    return;
++    return Error(
++        "Error parsing NetBSD core(5) notes: Unsupported procinfo version");
+ 
+-  offset += 4;
+-  thread_data.signo = data.GetU32(&offset);
++  uint32_t cpisize = data.GetU32(&offset);
++  if (cpisize != NETBSD::NT_PROCINFO_SIZE)
++    return Error(
++        "Error parsing NetBSD core(5) notes: Unsupported procinfo size");
++
++  cpi_signo = data.GetU32(&offset); /* killing signal */
++
++  offset += NT_PROCINFO_CPI_SIGCODE_SIZE;
++  offset += NT_PROCINFO_CPI_SIGPEND_SIZE;
++  offset += NT_PROCINFO_CPI_SIGMASK_SIZE;
++  offset += NT_PROCINFO_CPI_SIGIGNORE_SIZE;
++  offset += NT_PROCINFO_CPI_SIGCATCH_SIZE;
++  offset += NT_PROCINFO_CPI_PID_SIZE;
++  offset += NT_PROCINFO_CPI_PPID_SIZE;
++  offset += NT_PROCINFO_CPI_PGRP_SIZE;
++  offset += NT_PROCINFO_CPI_SID_SIZE;
++  offset += NT_PROCINFO_CPI_RUID_SIZE;
++  offset += NT_PROCINFO_CPI_EUID_SIZE;
++  offset += NT_PROCINFO_CPI_SVUID_SIZE;
++  offset += NT_PROCINFO_CPI_RGID_SIZE;
++  offset += NT_PROCINFO_CPI_EGID_SIZE;
++  offset += NT_PROCINFO_CPI_SVGID_SIZE;
++  cpi_nlwps = data.GetU32(&offset); /* number of LWPs */
++
++  offset += NT_PROCINFO_CPI_NAME_SIZE;
++  cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */
++
++  return Error();
+ }
+ 
+ static void ParseOpenBSDProcInfo(ThreadData &thread_data, DataExtractor &data) {
+@@ -524,12 +586,28 @@ static void ParseOpenBSDProcInfo(ThreadD
+ /// 1) A PT_NOTE segment is composed of one or more NOTE entries.
+ /// 2) NOTE Entry contains a standard header followed by variable size data.
+ ///   (see ELFNote structure)
+-/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
++Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
++    const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) {
++
++  assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
++
++  switch (GetArchitecture().GetTriple().getOS()) {
++  case llvm::Triple::NetBSD:
++    return ParseThreadContextsFromNoteSegmentNetBSD(segment_header,
++                                                    segment_data);
++  default:
++    return ParseThreadContextsFromNoteSegmentGeneric(segment_header,
++                                                     segment_data);
++  }
++}
++
++/// Generic (Linux, Android, FreeBSD, ...) Thread context from PT_NOTE segment
++/// 1) A Thread Context in a core file usually described by 3 NOTE entries.
+ ///    a) NT_PRSTATUS - Register context
+ ///    b) NT_PRPSINFO - Process info(pid..)
+ ///    c) NT_FPREGSET - Floating point registers
+-/// 4) The NOTE entries can be in any order
+-/// 5) If a core file contains multiple thread contexts then there is two data
++/// 2) The NOTE entries can be in any order
++/// 3) If a core file contains multiple thread contexts then there is two data
+ /// forms
+ ///    a) Each thread context(2 or more NOTE entries) contained in its own
+ ///    segment (PT_NOTE)
+@@ -540,8 +618,9 @@ static void ParseOpenBSDProcInfo(ThreadD
+ ///        new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
+ ///    For case (b) there may be either one NT_PRPSINFO per thread, or a single
+ ///    one that applies to all threads (depending on the platform type).
+-Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
++Error ProcessElfCore::ParseThreadContextsFromNoteSegmentGeneric(
+     const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) {
++
+   assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
+ 
+   lldb::offset_t offset = 0;
+@@ -607,21 +686,6 @@ Error ProcessElfCore::ParseThreadContext
+       default:
+         break;
+       }
+-    } else if (note.n_name.substr(0, 11) == "NetBSD-CORE") {
+-      // NetBSD per-thread information is stored in notes named
+-      // "NetBSD-CORE@nnn" so match on the initial part of the string.
+-      m_os = llvm::Triple::NetBSD;
+-      if (note.n_type == NETBSD::NT_PROCINFO) {
+-        ParseNetBSDProcInfo(*thread_data, note_data);
+-      } else if (note.n_type == NETBSD::NT_AUXV) {
+-        m_auxv = DataExtractor(note_data);
+-      } else if (arch.GetMachine() == llvm::Triple::x86_64 &&
+-                 note.n_type == NETBSD::NT_AMD64_REGS) {
+-        thread_data->gpregset = note_data;
+-      } else if (arch.GetMachine() == llvm::Triple::x86_64 &&
+-                 note.n_type == NETBSD::NT_AMD64_FPREGS) {
+-        thread_data->fpregset = note_data;
+-      }
+     } else if (note.n_name.substr(0, 7) == "OpenBSD") {
+       // OpenBSD per-thread information is stored in notes named
+       // "OpenBSD@nnn" so match on the initial part of the string.
+@@ -659,7 +723,7 @@ Error ProcessElfCore::ParseThreadContext
+         // The result from FXSAVE is in NT_PRXFPREG for i386 core files
+         if (arch.GetCore() == ArchSpec::eCore_x86_64_x86_64)
+           thread_data->fpregset = note_data;
+-        else if(arch.IsMIPS())
++        else if (arch.IsMIPS())
+           thread_data->fpregset = note_data;
+         break;
+       case NT_PRPSINFO:
+@@ -717,6 +781,136 @@ Error ProcessElfCore::ParseThreadContext
+   return error;
+ }
+ 
++/// NetBSD specific Thread context from PT_NOTE segment
++///
++/// NetBSD ELF core files use notes to provide information about
++/// the process's state.  The note name is "NetBSD-CORE" for
++/// information that is global to the process, and "NetBSD-CORE@nn",
++/// where "nn" is the lwpid of the LWP that the information belongs
++/// to (such as register state).
++///
++/// NetBSD uses the following note identifiers:
++///
++///      ELF_NOTE_NETBSD_CORE_PROCINFO (value 1)
++///             Note is a "netbsd_elfcore_procinfo" structure.
++///      ELF_NOTE_NETBSD_CORE_AUXV     (value 2; since NetBSD 8.0)
++///             Note is an array of AuxInfo structures.
++///
++/// NetBSD also uses ptrace(2) request numbers (the ones that exist in
++/// machine-dependent space) to identify register info notes.  The
++/// info in such notes is in the same format that ptrace(2) would
++/// export that information.
++///
++/// For more information see /usr/include/sys/exec_elf.h
++///
++Error ProcessElfCore::ParseThreadContextsFromNoteSegmentNetBSD(
++    const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) {
++
++  assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
++
++  lldb::offset_t offset = 0;
++  ArchSpec arch = GetArchitecture();
++  m_os = llvm::Triple::NetBSD;
++
++  /*
++   * To be extracted from struct netbsd_elfcore_procinfo
++   * Used to sanity check of the LWPs of the process
++   */
++  uint32_t nlwps = 0;
++  uint32_t signo;  /* killing signal */
++  uint32_t siglwp; /* LWP target of killing signal */
++
++  while (offset < segment_header->p_filesz) {
++    ELFNote note = ELFNote();
++    note.Parse(segment_data, &offset);
++
++    size_t note_start, note_size;
++    note_start = offset;
++    note_size = llvm::alignTo(note.n_descsz, 4);
++
++    // Store the NOTE information in the current thread
++    DataExtractor note_data(segment_data, note_start, note_size);
++    note_data.SetAddressByteSize(
++        m_core_module_sp->GetArchitecture().GetAddressByteSize());
++
++    llvm::StringRef name = note.n_name;
++
++    if (name == "NetBSD-CORE") {
++      if (note.n_type == NETBSD::NT_PROCINFO) {
++        Error error = ParseNetBSDProcInfo(note_data, nlwps, signo, siglwp);
++        if (error.Fail())
++          return error;
++      } else if (note.n_type == NETBSD::NT_AUXV) {
++        m_auxv = DataExtractor(note_data);
++      }
++    } else if (name.consume_front("NetBSD-CORE@")) {
++      lldb::tid_t tid;
++      if (name.getAsInteger(10, tid))
++        return Error("Error parsing NetBSD core(5) notes: Cannot convert "
++                     "LWP ID to integer");
++
++      switch (arch.GetMachine()) {
++      case llvm::Triple::x86_64: {
++        /* Assume order PT_GETREGS, PT_GETFPREGS */
++        if (note.n_type == NETBSD::AMD64::NT_REGS) {
++          m_thread_data.push_back(ThreadData());
++          m_thread_data.back().gpregset = note_data;
++          m_thread_data.back().tid = tid;
++        } else if (note.n_type == NETBSD::AMD64::NT_FPREGS) {
++          if (m_thread_data.empty() || tid != m_thread_data.back().tid)
++            return Error("Error parsing NetBSD core(5) notes: Unexpected order "
++                         "of NOTEs PT_GETFPREG before PT_GETREG");
++          m_thread_data.back().fpregset = note_data;
++        } else {
++          return Error(
++              "Error parsing NetBSD core(5) notes: Unsupported AMD64 NOTE");
++        }
++      } break;
++      default:
++        return Error(
++            "Error parsing NetBSD core(5) notes: Unsupported architecture");
++      }
++    } else {
++      return Error("Error parsing NetBSD core(5) notes: Unrecognized note");
++    }
++
++    offset += note_size;
++  }
++
++  if (m_thread_data.empty())
++    return Error("Error parsing NetBSD core(5) notes: No threads information "
++                 "specified in notes");
++
++  if (m_thread_data.size() != nlwps)
++    return Error("Error parsing NetBSD core(5) notes: Mismatch between the "
++                 "number of LWPs in netbsd_elfcore_procinfo and the number of "
++                 "LWPs specified by MD notes");
++
++  /* The whole process signal */
++  if (siglwp == 0) {
++    for (auto &data : m_thread_data)
++      data.signo = signo;
++  }
++  /* Signal destinated for a particular LWP */
++  else {
++    bool passed = false;
++
++    for (auto &data : m_thread_data) {
++      if (data.tid == siglwp) {
++        data.signo = signo;
++        passed = true;
++        break;
++      }
++    }
++
++    if (!passed)
++      return Error(
++          "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP");
++  }
++
++  return Error();
++}
++
+ uint32_t ProcessElfCore::GetNumThreadContexts() {
+   if (!m_thread_data_valid)
+     DoLoadCore();
diff --git a/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.h b/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.h
new file mode 100644
index 0000000000..5b542c7683
--- /dev/null
+++ b/lldb-git/patches/patch-source_Plugins_Process_elf-core_ProcessElfCore.h
@@ -0,0 +1,23 @@
+$NetBSD$
+
+--- source/Plugins/Process/elf-core/ProcessElfCore.h.orig	2017-02-02 23:56:41.000000000 +0000
++++ source/Plugins/Process/elf-core/ProcessElfCore.h
+@@ -125,6 +125,18 @@ private:
+     lldb_private::ConstString path;
+   };
+ 
++  // Parse thread(s) data structuresNetBSD(prstatus, prpsinfo) from given NOTE
++  // segment
++  lldb_private::Error ParseThreadContextsFromNoteSegmentNetBSD(
++      const elf::ELFProgramHeader *segment_header,
++      lldb_private::DataExtractor segment_data);
++
++  // Parse thread(s) data structuresGeneric(prstatus, prpsinfo) from given NOTE
++  // segment
++  lldb_private::Error ParseThreadContextsFromNoteSegmentGeneric(
++      const elf::ELFProgramHeader *segment_header,
++      lldb_private::DataExtractor segment_data);
++
+   //------------------------------------------------------------------
+   // For ProcessElfCore only
+   //------------------------------------------------------------------


Home | Main Index | Thread Index | Old Index