Hi All, I've been attempting to build uClibc on Ubuntu 12 (x64) so I can get some familiar tools on it. I've been having some issues, and they are expected.
Attached is a small program that reads unistd.h (from <linux>/asm/unistd.h) and writes it to sysnum.h (in <uClibc>/bits) for use by uClibc's build process. It's offered to others who might also find it useful. The program attempts to fill the gap of incomplete parsing by gen_bits_syscall_h.sh. In my particular case, a number of syscalls were missing, including __NR_open, __NR_dup, __NR_fstat, and __NR_pipe. The trick to using the program (uclibc-syscall) is to run `make`, wait for the errors due to missing __NR_* defines, and then run `uclibc-syscall.exe`. You wait for the errors from the build process because `make` creates a number of directories and symlinks, so its easiest to allow make to do the work (and create the bits/ directory). I hard coded the values for UNISTD_IN and SYSNUM_OUT. Please adjust to suite your taste. It would probably be best to read these from argv[1] and argv[2], but that would mean a lot more defensive programming due to the possible taint of argv[]. The defensive programming would include complete validation and compiler/linker hardening (https://www.owasp.org/index.php/C-Based_Toolchain_Hardening). Jeff
// Written and placed in public domain by Jeffrey Walton, noloa...@gmail.com // // uclibc-syscall attempts to address gaps in uClibc's gen_bits_syscall_h.sh script. // The uClibc script generates a file named sysnums.h, and includes the call gate // defines for open(), close(), dup(), etc. The gaps being addressed are missing // defines (for example, __NR_open, __NR_close, or __NR_dup). // // uclibc-syscall is complete but very *unintelligent*. It does not attempt to sort // out items such as: // #define __NR_open __NR3264_open // The program simply rejects the define when based on another define. Fortunately, // the strategy been successful so far. // // Change UNISTD_IN and SYSNUM_OUT to suite your taste (defined below). // // Debug builds: // g++ -O0 -g3 -ggdb -DDEBUG=1 -Wall -Wextra -Wconversion uclibc-syscall.cpp -o uclibc-syscall.exe // Release builds: // g++ -O2 -g -DNDEBUG=1 -Wall -Wextra -Wconversion uclibc-syscall.cpp -o uclibc-syscall.exe // #include <iostream> using std::cout; using std::cerr; using std::endl; #include <string> using std::string; #include <vector> using std::vector; #include <fstream> using std::ifstream; using std::ofstream; #include <sstream> using std::istringstream; #include <algorithm> using std::stable_sort; #include <stdexcept> using std::exception; using std::runtime_error; #include <cstdlib> #include <cstring> #include <cassert> #define UNUSED(x) ((void)(x)) ////////////////////////////////////////////////////////// struct Sysnum { Sysnum(const string& syscall, const string& number) : m_syscall(syscall), m_number(number) {} string m_syscall; string m_number; }; bool operator<(const Sysnum &lhs, const Sysnum &rhs) { assert(!lhs.m_syscall.empty()); assert(!rhs.m_syscall.empty()); if(lhs.m_syscall.empty()) throw runtime_error("operator<: lhs is not valid"); if(rhs.m_syscall.empty()) throw runtime_error("operator<: rhs is not valid"); if(lhs.m_syscall == rhs.m_syscall) { // Don't throw - treat a missing value as 0 (WTF???) assert(!lhs.m_number.empty()); assert(!rhs.m_number.empty()); istringstream lss(lhs.m_number), rss(rhs.m_number); int l=0, r=0; if(!lhs.m_number.empty()) lss >> l; if(!rhs.m_number.empty()) rss >> r; return l < r; } return strcmp(lhs.m_syscall.c_str(), rhs.m_syscall.c_str()) < 0; } ////////////////////////////////////////////////////////// typedef vector<Sysnum> SysnumVector; void ProcessFiles(const string& infile, const string& outfile); void SortSysnums(SysnumVector& sysnums); void WritePrologue(ofstream& outfile); void WriteSyscalls(ofstream& outfile, SysnumVector& sysnums); void WriteEpilogue(ofstream& outfile); ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// // Ubuntu: sudo apt-get install kernel-headers-$(uname -r) string UNISTD_IN = "/usr/src/linux-headers-3.2.0-38/include/asm/unistd.h"; // Fedora: su-; yum install hernel-headers // string UNISTD_IN = "/usr/include/linux/asm/unistd.h"; // string SYSNUM_OUT = "<uClibc>/include/bits/sysnum.h"; string SYSNUM_OUT = "./sysnum.h"; ////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { UNUSED(argc), UNUSED(argv); try { ProcessFiles(UNISTD_IN, SYSNUM_OUT); } catch(const exception& e) { cerr << e.what() << endl; exit(EXIT_FAILURE); } return EXIT_SUCCESS; } void ProcessFiles(const string& infile, const string& outfile) { assert(!infile.empty()); if(infile.empty()) throw runtime_error("filename (in) is not valid"); assert(!outfile.empty()); if(outfile.empty()) throw runtime_error("filename (out) is not valid"); ifstream instrm(infile.c_str()); assert(instrm.good()); if(!instrm.good()) throw runtime_error("Failed to open " + infile); ofstream outstrm(outfile.c_str(), ofstream::out | ofstream::trunc); assert(outstrm.good()); if(!outstrm.good()) throw runtime_error("Failed to open " + outfile); SysnumVector sysnums; do { string line; getline(instrm, line); assert(!instrm.bad()); if(instrm.bad()) throw runtime_error("Failed to process " + infile); // First smoke test. Throw out anything other than a define. string::size_type pos = line.find("#define"); if(pos == string::npos) continue; line = line.substr(pos+8, -1); // Throw out anything anything not a syscall value. pos = line.find("__NR_"); if(pos == string::npos) continue; // Tokenize on whitespace. pos = line.find_first_of(" \t\n\v\f\r", 0); if(pos == string::npos) continue; // This is __NR_*. For example, __NR_open. string syscall(line.substr(0, pos)); // Attempt to locate its define value pos = line.find_first_not_of(" \t\n\v\f\r", pos); if(pos == string::npos) continue; // This is what its defined to. It could be a // number, or it could be another define. string value(line.substr(pos, -1)); // This tests if its a number. x86_64 has a number // of defines based on other defines for x86/x64. // For example #define __NR_open __NR3264_open. istringstream iss(value); int t=0; iss >> t; if(iss.fail()) continue; // Paydirt. At this point we have a good tuple. // For example, {__NR_open,40}. Sysnum sysnum(syscall, value); sysnums.push_back(sysnum); } while(!instrm.eof()); SortSysnums(sysnums); WritePrologue(outstrm); WriteSyscalls(outstrm, sysnums); WriteEpilogue(outstrm); } void SortSysnums(SysnumVector& sysnums) { assert(!sysnums.empty()); if(sysnums.empty()) throw runtime_error("No system call numbers"); stable_sort(sysnums.begin(), sysnums.end()); } void WritePrologue(ofstream& outfile) { outfile << "/* WARNING!!! AUTO-GENERATED FILE!!! DO NOT EDIT!!! */" << endl; outfile << endl; outfile << "#ifndef _BITS_SYSNUM_H" << endl; outfile << "#define _BITS_SYSNUM_H" << endl; outfile << endl; outfile << "#ifndef _SYSCALL_H" << endl; outfile << "# error \"Never use <bits/sysnum.h> directly; include <sys/syscall.h> instead.\"" << endl; outfile << "#endif" << endl; } void WriteSyscalls(ofstream& outfile, SysnumVector& sysnums) { for(size_t i=0; i < sysnums.size(); i++) { const Sysnum& sysnum = sysnums[i]; assert(!sysnum.m_syscall.empty()); assert(!sysnum.m_number.empty()); outfile << endl; outfile << "#undef " << sysnum.m_syscall << endl; outfile << "#define " << sysnum.m_syscall << " "; outfile << sysnum.m_number << endl; string syscall(sysnum.m_syscall); syscall.replace(0, 4, "SYS"); outfile << "#define " << syscall << " "; outfile << sysnum.m_syscall << endl; } } void WriteEpilogue(ofstream& outfile) { outfile << endl; outfile << "#endif" << endl; outfile << endl; }
_______________________________________________ uClibc mailing list uClibc@uclibc.org http://lists.busybox.net/mailman/listinfo/uclibc